I am trying to find another solution to below Excel formula that was already provided here:
How do I create groups based on the sum of values?
It is the same requirement, but the grouping criteria needs to be an exact value.
Here's the sample data:
Column A | Column B
Item A | 1
Item B | 2
Item C | 3
Item D | 4
Item E | 5
Item F | 1
Item G | 2
Item H | 3
Item I | 4
Item J | 5
I need to group the rows if their Column B sum = 5.
Expected result:
Group 1 = Item A, Item D (1 + 4) = 5
Group 2 = Item B, Item C (2 + 3) = 5
Group 3 = Item E = 5
Group 4 = Item F, Item I (1 + 4) = 5
Group 5 = Item G, Item H (2 + 3) = 5
Group 6 = Item J = 5
If a row's Column B exceeds 5 or does not have another matching row to equal 5 when added then it will have no Group value.
Groupings can be interchangeable, ie. Group 1 = Item A, Item I can be made since 1 + 4 = 5.
I assume this can be achieved using Excel formulas but I am struggling to find which formula(s) can be used. Any help is appreciated!
I believe I was able to understand your question after some comments exchanged. Anyway I would recommend to update your question, it is an interesting problem, but the question was difficult to follow.
Before looking for an Excel solution, I took the approach of understanding the problem as a state machine with the transition from one state to another. I considered the following states that represent the position the item in the group. A group is defined as consecutive items that the sum of all items is equal to 5.
EMPTY: Just the initial situation
START: Start of the group
MIDDLE: A middle element of the group
END: The end of the group
START-END: A group with a single element
NA: Not applicable group
I follow the same idea of: How do I create groups based on the sum of values?, but slightly different helper columns:
Total (Column D), but for this case it is used the following formula: IF(SUM(C3,D2)>5,C3,SUM(C3,D2))
Status or item position within Group (Column G). Here is where it is calculated the corresponding status for each element
Checks for Valid Groups (Column H): Evaluates if a group is valid. When there is no match to 5, the group is not valid. It is indicated at the row that represents the beginning of the group (START or START-END states). If TRUE it means a valid group, if FALSE it is not a valid group, and NA for an NA value from Status column. If empty represents any element of the group that is not the first one.
Group # (Column I): To identify the group the row (Item) belongs to. Notice that we start counting the group from 1 and I also consider the case a group can not be formed (NA).
Here is a screenshot with the solution and the formula on G3:
=LET(total, D3, prevS, G2, QTY, C3,
IF(C3="", "",
IF(OR(AND(total=5, QTY<5, prevS="START"), AND(total=5, prevS="MIDDLE")), "END",
IF(OR(AND(total>5, total=QTY, OR(prevS="START", prevS="MIDDLE")),AND(total>5, OR(prevS="", prevS="END", prevS="NA", prevS="START-END"))), "NA",
IF(OR(AND(total<5, total=QTY, OR(prevS="START", prevS="MIDDLE")),AND(total<5, OR(prevS="", prevS="END", prevS="NA", prevS="START-END"))), "START",
IF(AND(total<5, OR(prevS="START", prevS="MIDDLE")), "MIDDLE",
IF(OR(AND(total=5, total= QTY, OR(prevS="START", prevS="MIDDLE")),AND(total=5, OR(prevS="", prevS="END", prevS="NA", prevS="START-END"))), "START-END", "UNDEFINED")
)
)
)
)
)
)
Notes::
LET Excel function is used to have something more readable
The IF blocks should to be ordered from the most specific case of total and QTY values to the most generic ones. For the case with same total condition, make sure the second condition for prevS are not repeated.
Added as a last resort UNDEFINED case, to check if any transition was not covered, if that is the case it has to be reviewed, so far in the sample data all cases are covered
Column K-Q is just for documenting purpose to identify all possible transitions. Column K-M provides all possible transitions organized them by previous status. The columns O-Q represent all possible transitions ordered by current status, so it is easier to formulate each portion of the IF blocks.
Maybe the formula can be simplified, compared to the solution provided by the similar question is more complex, but this question has more specific conditions. Some transitions maybe not relevant for the final result, but it is preferred to consider all positions in the group to make sure all transitions are covered.
The following state machine diagram shows all possible transitions:
Notes:
As you can see the solution also considers when a group cannot be created or non valid groups (NA values). The solution considers that Item column has only positive values, it is not stated in the question any restriction, but looking at the example they are all positives. To consider zero values, this solution needs to be adjusted.
Checks for Valid Groups column is calculated as follow:
= IF(G3="", "",
IF(G3="START-END", TRUE,
IF(G3="NA", "NA",
IF(G3="START",
LET(endRow, IFNA(MATCH("START", LEFT(G4:$G$1000,5),0), MATCH("", LEFT(G4:$G$1000,5),0))+ ROW()-1,
value, VLOOKUP("END", G4:INDIRECT( "G" & endRow),1,0),
IF(ISNA(value), FALSE, TRUE)
), ""
)
)
)
)
It identifies the start and end of the group, and then finds any NA values, if there are, then it is not a valid group. If the end of the candidate group is not found (the first MATCH returns N/A), then is searches until a blank row
Group # column is calculated has follow:
=IF(C3="","", LET(value, MAX($I$2:I2), IF(G3="NA", "NA",
IF(H3=TRUE, value + 1, IF(H3=FALSE, "NA",
IF(I2="NA", "NA", value))))))
This way only valid transaction are considered, i.e. the following status transitions starting from START but not ending in END : START->NA, START->MIDDLE[one or more]...->NA and NA are not considered valid groups (NA).
I added more examples from the original sample file provided, more can be added to further test all possible scenarios, but I guess you get the idea about this approach. As you sated "I assume this can be achieved using Excel formulas" yes it is possible, but I would say for more complex conditions I would suggest to implement a state machine algorithm in VBA. Even it is possible to do it with Excel functions, you have to deal with several nested IF blocks and helper columns, something that can be achieved with a simple for-loop in VBA.
Here is a link to online Excel file I used.
Is there a way to create a formula that:
Shows unique same number for each item
Creates a new ID (the max existing value for code +1) for a new item based on the existing codes and items.
For example:
Code
Item
1000
A
1001
B
1002
C
1000
A
1000
A
1002
C
So, if i add item "D" its code would be 1004, and so on...
One way would be defining a list against each letter. How many letter can be for your actual case? With your given sample data you can try below-
=XLOOKUP(B2,{"A","B","C","D","E","F"},{1000,1001,1002,1003,1004,1005})
Edit: You can also try-
=IF(B2:B20="","",1000+XMATCH(B2:B20,SORT(UNIQUE(B2:B20)),0))
I am a complete VBA beginner and this is the first time I have had to deal with VBA. My project is simple- a user form which heavily relies on dependent drop down lists. I watched a ton of videos and wrote (more like copy-pasted) code which actually works just fine. My issue is that I need to edit part of my code to add a feature which I have trouble finding a video on (trial and error editing only took me this far).
In it's current state, my form has two dropdown lists drawing information from a sheet where data is arranged in columns as follows:
ITEM ID | ITEM | CATEGORY
The user picks a category and then the item list if filtered based on the previous selection. I now need to rearrange those columns are add another one, making it the 1st tier selection as follows:
LOCATION | CATEGORY | ITEM ID | ITEM
Just rearranging the columns alone breaks my code. On top of that I need to add the Location combobox, which would filter the Categories, which in turn filter the Items.
This is the code which handles the CATEGORY and ITEM list:
Private Sub cmbEquipCategory_Change()
Dim sh As Worksheet
Dim lastBlankRow As Long
Me.cmbEquipment.Clear
Set sh = Sheets("Equipment_List")
lastBlankRow = sh.Cells(Rows.Count, 3).End(xlUp).Row
For i = 2 To lastBlankRow
If sh.Cells(i, 3) = Me.cmbEquipCategory.value Then
Me.cmbEquipment.AddItem sh.Cells(i, 2)
End If
Next i
End Sub
It is my impression that I need to alter this code to draw data from columns 2 and 4 (it currently does so from 3 and 2) and write another almost identical block of code which handles LOCATION and CATEGORY. Any advice, resources or help would be greatly appreciated. Thanks!
The way I do this is to used named ranges. So selecting your ITEM ID would lead to one of several ITEM ranges (I name them according to the ITEM ID options) which would lead to one of several CATEGORY ranges (I name these according to the ITEM options). The more options you have the more ranges you need. Named ranges aren't broken by adding in columns.
things="pen pencil apple mango litchi grapes pear song music"
stuff=things.split(" ")
items=["a","b","c","d"]
for word in items:
next_one=items.pop()
stuff.append(next_one)
print(stuff)
when I run this code, the resulting list shows that only last two elements are appended from items. Why is it not appending all the elements?
Therefore that you modify items reference You will only add two elements.
Below you can see all values in items variable in every step of loop.
STEP 1
items = ["a","b","c","d"]
next_one = 'd'
STEP 2
items = ["a","b","c"]
next_one = 'c'
STEP 3
items = ["a","b"]
So here the loop ends
To solve it you can change
for word in items:
to
while(items):
Or you can write it in one line:
stuff.extend(list(reversed(items)))
I was wondering how, or if at all possible, to create a pivotTable using VBA given a collection. Or improve on the current algorithm for my code.
Currently, I have a collection with about 28000 items. Each item has an unique Id, item number, and price. I want to generate a new collection with the unique Id, part number that has the lowest price. So I was thinking generating the pivotTable will aggregate all the item numbers, and find minimum price. Then based on that table, I can generate a new collection, or should I improve on the algorithm I have?
For example:
item[unique_id]: item number, price
Item[1]: 11111, 10
Item[2]: 22222, 2
Item[3]: 11111, 3
Item[4]: 11111, 15
Item[5]: 22222, 1
Item[6]: 33333, 2
and then the result collection would be something like:
Item[3]: 11111, 3
Item[5]: 22222, 1
Item[6]: 33333, 2
Currently, I have code that does the following to create that new collection
For Each Item in OriginalCollection
' Temp item holder for comparison
Set minItem = item
i = 1
Do While (i <= OriginalCollection.Count)
if OriginalCollection(i).itemNumber = minItem.itemNumber And OriginalCollection(i).price < minItem.price Then
Set minItem = OriginalCollection(i)
' reduce the size of collection, so fewer iterations
OriginalCollection.Remove (i)
OriginalCollection.Remove (minItem.Id)
End if
i = i + 1
Loop
If Not InCollection (MinCollection, minItem.Id) Then
MinCollection.Add minItem, minItem.Id
End If
Next item
Thank you in advance.
Anytime I need to accomplish what you're seeking, I just sort the table by item number, then price. I'm assuming your data are in cells A1:C28000. In a neighboring column's cell, starting with D2, I enter the formula: =if(b2=b1,"",1). This tells me when there's a change in item number. And every time there's a change in item number, I know I've found the cheapest price for the new item (because each group of item numbers is sorted by ascending price). Copy that formula in column D down the length of your item list.
Turn on your auto-filter and filter for where values in column D=1. Those are all of your lowest prices for each item. (adjust for if your very first item doesn't have a duplicate; i.e., just add column headers)
This approach doesn't use pivot tables, but based on your problem description, I'm not sure you need them.