For example please open thisIf there is N*N matrix as R(row) is given. So the program will find the minimum value in Rth row and then replace that particular column with 9999. I am getting #value error. How to rectify this?
I think there is some error in defining an array.
Please help me in this.
Function abc(N As Range, R As Integer) As Range
Dim c As Integer, i As Integer, min As Integer, ci As Integer, a As Integer,
j As Integer, y As Integer, z As Integer
a = N.Rows.Count
c = N.Columns.Count
Dim ab(1 To 1000, 1 To 1000) As integer
min = N(R, 1)
ci = 1
For i = 1 To c
If N(R, i) < min Then
min = N(R, i) And ci = i
End If
Next i
For y = 1 To a
For z = 1 To c
If z = ci Then
ab(y, z) = 9999
Else
ab(y, z) = N(y, z)
End If
Next z
Next y
abc = ab
End Function
Does this need to be VBA? Can be done with this formula (using your sample image, put this formula in cell D1 and copy over and down):
=IF(COLUMN(A1)=MATCH(MIN(INDEX($A$1:$B$2,2,0)),INDEX($A$1:$B$2,2,0),0),5432,INDEX($A$1:$B$2,ROW(A1),COLUMN(A1)))
Change both instances of $A$1:$B$2 to be the actual range the formula should be evaulating
Change 5432 to be the number you actually want returned (I got 5432 from your sample image, but your UDF shows 9999)
other than the output issue, your code is not consequent to your question wording
so either you
have to substitute the minimum value in a row with 9999
so your code can be reduced to
Function abc(N As Range, R As Integer) As Variant
Dim a As Long, c As Long, j As Long, min As Long, cj As Long
Dim ab As Variant
ab = N.value
a = UBound(ab, 1)
c = UBound(ab, 2)
min = ab(R, 1)
cj = 1
For j = 1 To c
If ab(R, j) < min Then
min = ab(R, j)
cj = j
End If
Next
ab(R, cj) = 9999
abc = ab
End Function
or you have to change ALL the range cells whose content matches the given row minimum value to this latter
Function abc2(N As Range, R As Integer) As Variant
Dim a As Long, c As Long, i As Long, j As Long, min As Long
Dim ab As Variant
ab = N.value
a = UBound(ab, 1)
c = UBound(ab, 2)
min = ab(R, 1)
For j = 1 To c
If ab(R, j) < min Then min = ab(R, j)
Next
For i = 1 To a
For j = 1 To c
If ab(i, j) = min Then ab(i, j) = 9999
Next
Next
abc2 = ab
End Function
Related
I've limited knowledge in maths so pardon the terms if i'm mistaken.
I need to create all possible combinations from multiple sets with at least 1 item included from that set.
- SetA: [1, 2, 3, 4, 5, 6, 7]
- SetB: [a, b, c, d]
- SetC: [!, #, #, $, %]
Example Output:
- [1,a,!]
- [1,2,a,c,#]
- [1,2,3,4,5,6,7,a,b,c,d,!,#,#,$,%]
Is there a specific combination formula for this since i can only come up with nested loops and i'm not sure if it is even correct.
#barrycarter had good idea of obtaining the power set. However, we don't need to reject anything as we are not getting the power set of the union of sets (this would end up being inefficient as there will be many rejects as the number of sets grows). We simply get the power set of each set, then get all combinations of those power sets. The subroutine below, works for an arbitrary number sets of arbitrary length.
Sub CreateAllCombs()
Dim ArrayOfPowSets() As Variant, mySet() As Variant, ArrCounter() As Long, myPS As Variant
Dim myCombs() As Variant, nextComb() As Variant, ParentComb() As Variant, ArrMax() As Long
Dim i As Long, j As Long, k As Long, count1 As Long, count2 As Long, CombExist As Boolean
Dim tempCol As Long, myMax As Long, maxRow As Long, totalCombs As Long
With ActiveSheet
maxRow = .Cells(.Rows.count, "A").End(xlUp).Row
End With
ReDim ArrayOfSets(1 To maxRow, 1 To 1)
ReDim ArrCounter(1 To maxRow)
ReDim ArrMax(1 To maxRow)
myMax = 0
For i = 1 To maxRow
With ActiveSheet
tempCol = .Cells(i, .Columns.count).End(xlToLeft).Column
End With
ReDim mySet(1 To tempCol)
For j = 1 To tempCol: mySet(j) = Cells(i, j): Next j
myPS = PowerSet(mySet)
ArrMax(i) = UBound(myPS)
If ArrMax(i) > myMax Then
myMax = ArrMax(i)
ReDim Preserve ArrayOfPowSets(1 To maxRow, 1 To ArrMax(i))
End If
For j = 1 To ArrMax(i)
ArrayOfPowSets(i, j) = myPS(j)
Next j
ArrCounter(i) = 1
Next i
CombExist = True
totalCombs = 0
Do While CombExist
count1 = 1
ReDim ParentComb(1 To 1)
For i = 1 To maxRow - 1
For j = 1 To UBound(ArrayOfPowSets(i, ArrCounter(i)))
ReDim Preserve ParentComb(1 To count1)
ParentComb(count1) = ArrayOfPowSets(i, ArrCounter(i))(j)
count1 = count1 + 1
Next j
Next i
For i = 1 To ArrMax(maxRow)
count2 = count1
nextComb = ParentComb
For j = 1 To UBound(ArrayOfPowSets(maxRow, i))
ReDim Preserve nextComb(1 To count2)
nextComb(count2) = ArrayOfPowSets(maxRow, i)(j)
count2 = count2 + 1
Next j
totalCombs = totalCombs + 1
ReDim Preserve myCombs(1 To totalCombs)
myCombs(totalCombs) = nextComb
Next i
k = maxRow - 1
Do While (ArrCounter(k) >= ArrMax(k))
ArrCounter(k) = 1
k = k - 1
If k = 0 Then Exit Do
Loop
If k > 0 Then ArrCounter(k) = ArrCounter(k) + 1 Else CombExist = False
Loop
Sheets("Sheet2").Select
For i = 1 To totalCombs
For j = 1 To UBound(myCombs(i))
Cells(i, j) = myCombs(i)(j)
Next j
Next i
End Sub
I used a slightly modified version of the power set function written by John Coleman found here
Function PowerSet(Items As Variant) As Variant
Dim PS As Variant
Dim i As Long, j As Long, k As Long, n As Long
Dim subset() As Variant
n = UBound(Items)
ReDim PS(1 To 1 + 2 ^ n - 2)
For i = 1 To 2 ^ n - 1
ReDim subset(1 To n)
k = 0
For j = 0 To n - 1
If i And 2 ^ j Then
k = k + 1
subset(k) = Items(j + 1)
End If
Next j
ReDim Preserve subset(1 To k)
PS(i) = subset
Next i
PowerSet = PS
End Function
This assumes that SetA is on row 1, SetB is on row 2, etc. Observe:
Additionally, the reader should be warned that this may take a while as there is over 14 million possible combinations.
(2^3 - 1) * (2^5 - 1) * (2^16 - 1) = 7 * 31 * 65535 = 14221095
Also, all combinations are written out generically to Sheet2.
I think i found my solution please verify.
First, for each sets, i created all possible combinations and checked the length using the sum of pascal triangle without the null or this formula:
n!/(r!(n-r)!) - 1
e.g.
SetB: [a, b, c, d] -> [a,b,c,d,ab,ac,ad,bc,bd,cd,abc,abd,acd,bcd,abcd]
After creating all possible combinations for each sets, I just used product rule
[SetA] X [SetB] X [SetC]
Which resulted for all possible combinations for:
multiple items
multiple sets
no repeat
no order
Reference: https://www.mathsisfun.com/combinatorics/combinations-permutations-calculator.html
EDIT1: checking for amount of combinations per set can also be (2^n)-1 where n= length of set
Have you tried using nested for loops.
Sub Hello()
MsgBox ("Hello, world!")
Dim arr1
arr1 = Array("1", "2", "3")
Dim arr2
arr2 = Array("a", "b", "c")
Dim arr3
arr3 = Array("!", "#", "$")
For i = 0 To UBound(arr1)
For j = 0 To UBound(arr2)
For k = 0 To UBound(arr3)
MsgBox (arr1(i) & arr2(j) & arr3(k))
Next
Next
Next
End Sub
Column header for different sheet
iI have many rows having data in sheet 2 and iI want the column name of the max of a row (i.e. from column from column name of B2 to AH2 inside if loop).
Sub shanaya()
Dim j As Integer
Dim i As Integer
Dim z As Integer
Dim x As Integer
z = 35
For i = 11 To 28
For j = 2 To 19
If Sheet8.Cells(j, 1) = Sheet1.Cells(i, 1) Then
Sheet1.Cells(i, 10) = Sheet8.Cells(j, z)
Max [(Sheet8.Cells(J,2)): (Sheet8.Cells(j,z))]
Sheet1.Cells(i,13) = column header of max function
End If
Next j
Next i
End Sub
Using MATCH worksheet function will give you the column matching the MAX :
There is a +1 because your range start at col 2! ;)
Sub shanaya()
Dim j As Integer
Dim i As Integer
Dim z As Integer
Dim x As Integer
Dim ColOfMax As Integer
Dim RgToSearch As Range
z = 35
For i = 11 To 28
For j = 2 To 19
If Sheet8.Cells(j, 1) = Sheet1.Cells(i, 1) Then
Sheet1.Cells(i, 10) = Sheet8.Cells(j, z)
Set RgToSearch = Sheet8.Range(Sheet8.Cells(j, 2), Sheet8.Cells(j, z))
ColOfMax = Application.WorksheetFunction.Match(Application.WorksheetFunction.Max(RgToSearch), RgToSearch, 0) + 1
Sheet1.Cells(i, 13) = Sheet8.Cells(1, ColOfMax)
End If
Next j
Next i
End Sub
I have sample table as below
Type Format W D L Gauge
Roxy Rubbers 31 1 1 3
Roxy Rubbers 36 0 48 4
Roxy Rubbers 36 1 1 3
Here is my sub
Sub Calculate()
Dim Format, Gauge, Width, Depth, Length As String
Format = Sheets("inputs").Range("H26")
Gauge = Sheets("inputs").Range("I26")
Width = Sheets("inputs").Range("J26")
Depth = Sheets("inputs").Range("K26")
Length = Sheets("inputs").Range("L26")
Dim vArray() As Variant
vArray = Range("myRange")
Dim i As Long
For i = LBound(vArray, 1) To UBound(vArray, 1)
Debug.Print vArray(i, 1)
Next
End Sub
How do I find nearest row using VBA?
Gauge and format needs to be exact match and for W/D/L need to return nearest match
Example:
For Rubbers, 3 gauge, 30x12x12 input it should return first row as result
Assuming that by "nearest" you meant nearest volume (in the case of no exaxt matching), I suggest this function that returns the right range given those parameters. Note that I assumed that your "Gauge" column is next to the "Format" one (columns H and I as in your code) while your pictures shows that gauge comes last...
Option Explicit
Function findNearestRow(FindIn As Range, Format As String, _
Gauge As String, Width As Double, Depth As Double, Length As Double) As Range
Dim F As String, G As String, W As Double, D As Double, L As Double
Dim i As Long, best As Long, vol As Double, diff As Double, minDiff As Double
minDiff = 99999999
vol = Width * Depth * Length
For i = 1 To FindIn.Rows.Count
F = FindIn.Cells(i, 1).Value
G = FindIn.Cells(i, 2).Value
If F = Format And G = Gauge Then
W = FindIn.Cells(i, 3).Value
D = FindIn.Cells(i, 4).Value
L = FindIn.Cells(i, 5).Value
If W = Width And D = Depth And L = Length Then
Set findNearestRow = FindIn.Rows(i)
Exit Function
End If
diff = Abs(W * D * L - vol)
If diff < minDiff Then
minDiff = diff
best = i
End If
End If
Next
If minDiff < 1000 Then Set findNearestRow = FindIn.Rows(best)
' Else it returns null, nearest matching too far
End Function
Sub Test()
Dim r As Range
Set r = findNearestRow(FindIn:=Range("H2:L20"), _
Format:=Sheets("inputs").Range("H26"), _
Gauge:=Sheets("inputs").Range("I26"), _
Width:=Sheets("inputs").Range("J26"), _
Depth:=Sheets("inputs").Range("K26"), _
Length:=Sheets("inputs").Range("L26"))
If r Is Nothing Then
MsgBox "no matching found"
Else
r.Select
End If
End Sub
You could first AutoFilter() the exact matches and then loop through filtered cells for the nearest triple:
Option Explicit
Sub Calculate()
Dim Format As String
Dim Gauge As Long, Width As Long, Depth As Long, Length As Long
Dim nearestRate As Double
Dim nearestRng As Range, cell As Range
With Sheets("inputs")
Format = .Range("H26").Value2
Gauge = .Range("I26").Value2
Width = .Range("J26").Value2
Depth = .Range("K26").Value2
Length = .Range("L26").Value2
With .Range("F1", .Cells(.Rows.Count, "A").End(xlUp))
.AutoFilter field:=2, Criteria1:=Format
.AutoFilter field:=6, Criteria1:=Gauge
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then
nearestRate = 100000000#
For Each cell In .Resize(.Rows.Count - 1, 1).Offset(1, 2).SpecialCells(xlCellTypeVisible)
UpdateNearest cell, Width, Depth, Length, nearestRate, nearestRng
Next
End If
End With
End With
End Sub
Function UpdateNearest(rng As Range, refVal1 As Long, refVal2 As Long, refVal3 As Long, nearestRate As Double, nearestRng As Range) As Long
Dim rate As Double
rate = Sqr((rng.Value - refVal1) ^ 2 + (rng.Offset(, 1).Value - refVal1) ^ 2 + (rng.Offset(, 2).Value - refVal2) ^ 2)
If rate < nearestRate Then
nearestRate = rate
Set nearestRng = rng
End If
End Function
the UpdateNearest() function assumes a criteria of minimum differences squares sum. but you can adapt to your actual (and unknown) needs
I am trying to calculate Mahalanobis distances in VBA.
I have created my UDF to calculate Covarince matrix but i got a #value error when executing my function.
could you give me some help
Thanks in advance!
Function DMahalanobis(x As Range, y As Range) As Variant
Dim c() As Variant, k As Variant, U As Range, a() As Variant, b() As Variant
Set U = Application.Union(x, y)
Debug.Print U
k = x.Columns.Count
a = x
b = y
ReDim c(1, k)
For i = 1 To k Step 1
c(1, i) = a(1, i) - b(1, i)
Next i
DMahalanobis = Application.MMult(Application.MMult(Application.Transpose(c), Application.MInverse(MVARCOVAR(U))), c)
End Function
This is my VarCovar function that works fine
'Function to calculate Covariance matrix
Function MVARCOVAR(RANGO As Range) As Variant
Dim c() As Variant, i As Long, k As Long, j As Long
k = RANGO.Columns.Count
Debug.Print k
ReDim c(k, k)
For i = 1 To k Step 1
For j = 1 To k Step 1
c(i, j) = Application.Covar(Application.Index(RANGO, , i), Application.Index(RANGO, , j))
Next j
Next i
MVARCOVAR = c
End Function
may due to the singular issue in the line:
DMahalanobis = Application.MMult(Application.MMult(Application.Transpose(c), Application.MInverse(MVARCOVAR(U))), c).
Based on your given input, dimension of U is 2xk, as 2<<k, the covariance matrix of U may contain some missing value, when you take the inverse, it will pop up an error. Maybe you can try to change U to the whole data set, otherwise you cannot capture the distribution information in the data when calculating mahalanobis distance.
I need help with a macro that exports all combinations of a range in same row each one ( I mean horizontal exports).
Every combination I want to be in one cell each time.
I want to change any time the number of strings in the range and also the number of strings combinations (In the example below 4 strings in the range and 3 for combinations)
1. A B C D -------------ABC --ABD--ACD--BCD
2. E F G H--------------EFG---EFH--EGH--FGH
3. I G K L----------------IGK----IGL---IKL---GKL
Below its a module that I found in web that is very close to what I need.
I am very new to Vba macros and I cannot achieve what I am looking for with the below code
Private NextRow As Long
Sub Test()
Dim V() As Variant, SetSize As Integer, i As Integer
SetSize = Cells(2, Columns.count).End(xlToLeft).Column
ReDim V(1 To SetSize)
For i = 1 To SetSize
V(i) = Cells(2, i).Value
Next i
NextRow = 4
CreateCombinations V, 3, 3
End Sub
Sub CreateCombinations( _
OriginalSet() As Variant, _
MinSubset As Integer, MaxSubset As Integer)
Dim SubSet() As Variant, SubSetIndex As Long
Dim SubSetCount As Integer, Bit As Integer
Dim k As Integer, hBit As Integer
Dim MaxIndex As Long
hBit = UBound(OriginalSet) - 1
ReDim SubSet(1 To UBound(OriginalSet))
MaxIndex = 2 ^ UBound(OriginalSet) - 1
For SubSetIndex = 1 To MaxIndex
SubSetCount = BitCount(SubSetIndex)
If SubSetCount >= MinSubset And SubSetCount <= MaxSubset Then
k = 1
For Bit = 0 To hBit
If 2 ^ Bit And SubSetIndex Then
SubSet(k) = OriginalSet(Bit + 1)
k = k + 1
End If
Next Bit
DoSomethingWith SubSet, SubSetCount
End If
Next SubSetIndex
End Sub
Sub DoSomethingWith(SubSet() As Variant, ItemCount As Integer)
Dim i As Integer
For i = 1 To ItemCount
Cells(NextRow, i) = SubSet(i)
Next i
NextRow = NextRow + 1
End Sub
Function BitCount(ByVal Pattern As Long) As Integer
BitCount = 0
While Pattern
If Pattern And 1 Then BitCount = BitCount + 1
Pattern = Int(Pattern / 2)
Wend
End Function
Here is a way to do it:
In your excel sheet, add an array formula like this:
A B C D E
1
2 A B C D {=k_combinations(CONCATENATE(A2;B2;C2;D2);3)}
3 E F G H {=k_combinations(CONCATENATE(A3;B3;C3;D3);3)}
Note that you should extend the array formula to columns F, G, H and so on so that you get all results. (The { and } are not to be inserted manually, they are the mark of the array formula) :
Select cells E2, F2, G2, H2, and so on to Z2
Type the formula
To validate input, press Ctrl+Shift+Enter
Put the following code into a code module.
Public Function k_combinations(ByVal chLetters As String, ByVal k As Long) As Variant
Dim chCombinations() As String
Dim uCount As Long
Dim vReturn() As Variant
Dim i As Long
uCount = Get_k_combinations(chLetters, chCombinations, k)
ReDim vReturn(0 To uCount - 1) As Variant
For i = 0 To uCount - 1
vReturn(i) = chCombinations(i)
Next i
k_combinations = vReturn
End Function
Private Function Get_k_combinations(chLetters As String, chCombinations() As String, ByVal k As Long) As Long
Dim i As Long
Dim M As Long
M = Len(chLetters)
If k > 1 Then
Get_k_combinations = 0
For i = 1 To M - (k - 1)
Dim chLetter As String
Dim uNewCombinations As Long
Dim chSubCombinations() As String
Dim j As Long
chLetter = Mid$(chLetters, i, 1)
uNewCombinations = Get_k_combinations(Right$(chLetters, M - i), chSubCombinations, k - 1)
ReDim Preserve chCombinations(0 To Get_k_combinations + uNewCombinations) As String
For j = 0 To uNewCombinations - 1
chCombinations(Get_k_combinations + j) = chLetter & chSubCombinations(j)
Next j
Get_k_combinations = Get_k_combinations + uNewCombinations
Next i
Else
ReDim chCombinations(0 To M - 1) As String
For i = 1 To M
chCombinations(i - 1) = Mid$(chLetters, i, 1)
Next i
Get_k_combinations = M
End If
End Function
Get_k_combinations is called recursively. The performance of this method is quite poor (because it uses string arrays and makes a lot of reallocations). If you consider bigger data sets, you will have to optimize it.