How to find which value creates maximum combination - Excel VBA - excel

I need to find which value creates the maximum combination shown below in Excel Vba
suppose,
I have combinations like this
a a+b a+b+c 1 1+2 1+2+1 3 4
b a+c a+b+d 2 1+1 1+2+3 2 6
c a+d a+b+e 1 1+3 1+2+2 4 5
d a+e a+c+d 3 1+2 1+1+3 3 5
e b+c a+c+e 2 2+1 1+1+2 3 4
b+d a+d+e 2+3 1+3+2 5 6
b+e b+c+d 2+2 2+1+3 4 6
c+d b+c+e 1+3 2+1+2 4 5
c+e b+d+e 1+2 2+3+2 3 7
d+e c+d+e 3+2 1+3+2 5 6
I need to find which combinations creates maximum value, In this case the value "7" is maximum which is created by 2,3,2. Hence I want these value as a output in unique cells.
I may have thousands of combinations, hence i want these to be found automatically and to be output in unique cells automatically and run the program further.
Please help.
Thanks
Balaji

Concept :
The greatest sum of m values within a set of n is the sum of the m bigger values.
Once the values are ordered in descending order, the solution is trivial.
Here is a pure Excel solution, without VBA.
Design & Implementation :
The user input (variable names and values) are in C4:D8.
The idea is the following:
Determine the order of data. For this, I use RANK in the column B.
Then use VLOOKUP in columns G and H to sort the data according to rank.
Then the maximum sums are trivial to compute in : sum of the n bigger numbers.
Here is the code:
A B C D E F G H I J K
1
2 User input Sorted by rank Maximum sums
3 Rank name value Rank name value name value
4 =RANK.EQ(C4;$C$4:$C$8) a 45 1 =VLOOKUP(E4;$A$4:$C$8;2;FALSE) =VLOOKUP(E4;$A$4:$C$8;3;FALSE) 2 numbers =CONCATENATE($F$4;"+";$F$5) =$G$4+$G$5
5 =RANK.EQ(C5;$C$4:$C$8) b 1 2 =VLOOKUP(E5;$A$4:$C$8;2;FALSE) =VLOOKUP(E5;$A$4:$C$8;3;FALSE) 3 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6) =$G$4+$G$5+$G$6
6 =RANK.EQ(C6;$C$4:$C$8) c 2 3 =VLOOKUP(E6;$A$4:$C$8;2;FALSE) =VLOOKUP(E6;$A$4:$C$8;3;FALSE) 4 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6;"+";$F$7) =$G$4+$G$5+$G$6+$G$7
7 =RANK.EQ(C7;$C$4:$C$8) d 12 4 =VLOOKUP(E7;$A$4:$C$8;2;FALSE) =VLOOKUP(E7;$A$4:$C$8;3;FALSE) 5 numbers =CONCATENATE($F$4;"+";$F$5;"+";$F$6;"+";$F$7;"+";$F$8) =$G$4+$G$5+$G$6+$G$7+$G$8
8 =RANK.EQ(C8;$C$4:$C$8) e 33 5 =VLOOKUP(E8;$A$4:$C$8;2;FALSE) =VLOOKUP(E8;$A$4:$C$8;3;FALSE)
Here is how the result looks:
A B C D E F G H I J K
1
2 User input Sorted by rank Maximum sums
3 Rank name value Rank name value name value
4 1 a 45 1 a 45 2 numbers a+e 78
5 5 b 1 2 e 33 3 numbers a+e+d 90
6 4 c 2 3 d 12 4 numbers a+e+d+c 92
7 3 d 12 4 c 2 5 numbers a+e+d+c+b 93
8 2 e 33 5 b 1
Note that it can be easily extended to more variables.

Expanding on d-stroyer's answer, and converting it to VBA:
create UDF:
Option Explicit
Function GetMax(RNames As Range, RVals As Range, MaxNums As Long) As String
Dim i As Long
Dim j As Long
Dim tmpName As String
Dim tmpVals As Long
Dim Names()
Dim Vals()
Names = RNames
Vals = RVals
For i = 1 To UBound(Names) - 1 'bubble sort
For j = i + 1 To UBound(Names)
If Vals(i, 1) < Vals(j, 1) Then 'largest first
tmpName = Names(i, 1)
Names(i, 1) = Names(j, 1)
Names(j, 1) = tmpName
tmpVals = Vals(i, 1)
Vals(i, 1) = Vals(j, 1)
Vals(j, 1) = tmpVals
End If
Next j
Next i
For i = 1 To MaxNums
If Vals(i, 1) <= 0 Then Exit For
'adding zero, or negative numbers will lower the total
Next i
For j = 1 To i - 1
GetMax = GetMax & Names(j, 1) & ","
'now we know how many values to use (from previous loop)
'make the string up
Next j
If Len(GetMax) > 0 Then
GetMax = Left(GetMax, Len(GetMax) - 1)
'remove the final comma
Else
GetMax = "No result found"
End If
End Function
Call using =getmax(A1:A5,D1:D5,3)
result would be d,b,e
I'll leave the rest up to you ov checking for error conditions, such as more than 1 column passed in the range, or ranges of unequal size, or a max # of items returned being larger than the range size

Related

Excel formula for trend?

does any one can suggest me any formula in excel to use for following question.
I have a data list with historical numbers for each particular example. I would need in column G Categoraise in 3 Categories Increasing, Decreasing, Various:
For exmaple
Column A Column B Column C Column D Column E Column F Column G
month 1 month2 month3 month4 month5 Category
Example 1 3 1 2 0 4 Various
Example 2 6 4 3 1 0 Decreasing
Example 3 0 0 3 5 10 Increasing
I am not sure that trend focmula is a correct one.
Any kind suggestion?
Use nested IFS with SUMPRODUCT:
=IF(AND(SUMPRODUCT(--(B2:E2<C2:F2)),SUMPRODUCT(--(B2:E2>C2:F2))),"Various",IF(SUMPRODUCT(--(B2:E2<C2:F2)),"increasing",IF(SUMPRODUCT(--(B2:E2>C2:F2)),"decreasing","even")))
Here is a VBA solution which can be used directly on the worksheet:
Function ClassifySequence(nums As Range) As String
Dim i As Long, minDelta As Long, maxDelta As Long
Dim delta As Variant
With Application.WorksheetFunction
maxDelta = .Min(nums) - .Max(nums)
minDelta = -maxDelta
End With
For i = 1 To nums.Cells.Count - 1
delta = nums.Cells(i + 1).Value - nums.Cells(i).Value
If delta < minDelta Then minDelta = delta
If delta > maxDelta Then maxDelta = delta
Next i
If maxDelta <= 0 Then
ClassifySequence = "Decreasing"
ElseIf minDelta >= 0 Then
ClassifySequence = "Increasing"
Else
ClassifySequence = "Various"
End If
End Function
For example,
In this code I decided to classify a constant sequence as decreasing. That could of course be changed, either to "Various" or "Increasing" or by creating a fourth category as in Scott Craner's excellent answer.

How can I create a list of numbers that is like the following?

I want to create a list of number like this in Excel, in separate cells:
(column B);
1
1
2
1
2
3
1
2
3
4
.
.
.
.
If you can't see each number is sequences from one up to the number your on.
Using formulas only, no VBA:
In column B:
1 | 1
2 | 1
3 | =IF(B2-MAX(B$1:B1)<1,B2+1,1)
Then fill that formula down
If you want just one formula that stands on its own (without referencing other cells), you can evaluate the triangle sequence at term n = ROW() with this more imposing formula:
=IFERROR(ROW() - COMBIN(INT((1+SQRT(8*ROW()))/2), 2),1)
(The IFERROR part just handles the first term, which attempts to evaluate COMBIN(1,2) )
x = 1 'the starting row value
y = 2 'the starting column value
z = 9 'the number of entries you ultimately want to make
entryMax = 1 'the max number of this sequence
entryStart = 1 'the start of the sequence
Do While x<=z
entryStart = 1 'reset the value of entryStart
Do While entryStart <= entryMax
cells(x, y) = entryStart
x= x + 1
entryStart = entryStart + 1
Loop
entryMax = entryMax + 1
Loop
If you start with the number 1 in B1 then put
=B1*10+ROW()
in B2 you can drag this down
But you don't state what the pattern should be after B9

Auto-increment based on other column repeats

I need a macro or formula that can do this:
Column A Values:
1
1
1
2
2
2
3
3
4
4
4
5
5
6
6
I need Column B to do:
1
2
3
1
2
3
1
2
1
2
3
1
2
1
2
Because column B has to have an increment number while column A has the same repeated value (for example 1 1 1 2), when it changes (to 2 or 3 etc.) the counter on column B has to reset and increment itself while A repeats the next value (1 2 3 1)
Thanks
Edit
Have a look at bzimor's answer as he solves is in a more general way without a hard value in column B1!
Original Answer
You can solve it the following way without VBA:
Put a hard value of 1 in column B1. This is your start value and should be always correct because you start counting with 1.
Then enter the following formula in B2
=IF($A2=$A1;$B1+1;1)
Just drag the formula down to the other rows of B and you're done
So B3 should look like this
=IF($A3=$A2;$B2+1;1)
and so on ...
You can use single formula:
=COUNTIF($A$1:A1,A1)
Put it into cell B1 and fill down
Here is your desired macros
Sub jkjainGenerateSerialNumber20161124()
readcol = Val(InputBox("type ref col#"))
writecol = Val(InputBox("type dest col#"))
ts = 0
Range("A1000000").Select
Selection.End(xlUp).Select
lastrow = ActiveCell.Row
For n = 2 To lastrow
prev = Cells(n - 1, readcol)
curr = Cells(n, readcol)
If prev <> curr Then
ts = 1
End If
If prev = curr Then
ts = ts + 1
End If
Cells(n, writecol) = ts
Next
End Sub

Excel for loop to get value from another row

I have an spreadsheet that contains various data. It looks like this:
A A A B B C C C C
a 1 2 3 2 1 4 2 3 2
b 0 2 3 3 0 1 2 3 0
c 6 6 3 0 2 1 0 4 0
etc.
What I want is to add all the Aa's and come up with a Aa total, all the Bb's and come up with a Bb total, all the Ab's etc.
What I want to do is, for every column, check if it is A, B or C. I want to do that because the data may change I might end up with four columns for A, two for B, etc. I know however that a, b and c will stay where they are.
I also don't know the order of A, B and C. There could be two A's followed by two C's and then one B.
My final result will be a table containing all the totals:
Aa Ab Ac
Ba Bb Bc
Ca Cb Cc
Where in the previous example would mean that Aa = 1 + 2 + 3 = 6, Ab = 5, etc.
Something like that.
I think the way to go is for 1-1 (the total of Aa's) is to go through every column in the first row. Check if it is an A. If it is, then get the value of the same column but second row. Add it to the total. When gone through all the columns, show up the total in 1-1.
What I have so far (for A):
Sub getA()
Dim x As Integer
Dim total As Integer
'cols = Find number of columns with data in them
For x = 1 To cols
'cell = cell in Ax
If InStr(1, cellvalue, "a") = 1 Then
'val = value from row 5 in same column
total = total + Val
End If
Next
End Sub
But I don't really know how to proceed with the commented lines.
Finally, another thing I would like to know is how will these values be presented in their respective cells without any extra event being carried (button for example). They should just appear in their cells from the moment someone opens the spreadsheet.
Any help is greatly appreciated.
Thanks.
Just an FYI, this can be done using the SUMPRODUCT formula:
=SUMPRODUCT(($B$1:$J$1=D$9)*($A$2:$A$4=$C10)*$B$2:$J$4)
EDIT
To compare the first letter then use this formula:
=SUMPRODUCT((LEFT($B$1:$J$1,1)=D$9)*($A$2:$A$4=$C10)*$B$2:$J$4)
Are you looking for something like:
Function countletter(strLetter As String) As Double
Dim x As Double, y As Double, xMax As Double, yMax As Double
xMax = Range("A1").CurrentRegion.Columns.Count
yMax = Range("A1").CurrentRegion.Rows.Count
For x = 1 To xMax
For y = 1 To yMax
If Cells(y, x).Value = strLetter Then
countletter = countletter + 1
End If
Next
Next
End Function

Excel VBA Macro to add a row when value changes and populate that row

I'm trying to build a macro in excel that will take a bunch of data like this:
D 1 2 3 4 5
D 1 2 3 9 5
D 1 2 3 4 5
And process it to insert a row when a value in column 4 differs. I also want to populate this row at the same time with either static values or a formula.
So ideally, taking the above table I would get:
D 1 2 3 4 5
H A B C D E <- This row got added as there was a change in column D
D 1 2 3 9 5
H A B C D E <- This row got added as there was a change in column D
D 1 2 3 4 5
I would want this to iterate through a quite long list.
Can anyone give me any pointers?
Thank you for your help.
Something like this should work. I didn't test it but if you run it and use F8 to iterate through it should be easy to debug if it doesn't work exactly as intended.
Dim i as integer
for i = 2 to cells(1,1).end(xldown).row 'itereate thru all rows
if cells(i,4).value <> cells(i-1,4).value then 'compare the cells in col 4 with previous row
rows(i).entirerow.insert 'insert a row if the values don't match
cells(i,1) = "A"
cells(i,2) = "B"
cells(i,3) = "C"
cells(i,4) = "D"
cells(i,5) = "E"
i = i + 1 'since we inserted a row we have to make i bigger to go down
end if
next i

Resources