Excel "UnCONCATENATE"/explode in function / Convert cell into array - excel

I am trying to "Unconcatenate" a string in Excel 2010. Yes, I know that is not a real word. So pretty much; I have a cell that can not be split into multiple columns the cell looks like this:
Item 1, Item 2, Item 3
Now this cell may have 0-? items. I am wanting to compare that one cell against a column in another sheet. I believe I would need to use the match function to do this, but I need that first cell to be converted into an array in a function with the delimiter as the comma.
So far I have =MATCH(Each item in cell, SHEET2!A:A, 0)
Any help would be nice. I am aware of =Left and =Right, but I do not think these will work because the number of items in each cell may not be the same. Thanks
Edit:
Detailed discription:
In my first sheet I have a dropdown box. When you choose items it does a vlookup on sheet 2 on this item. When this happens I want it to also check if cell E in that row (item 1, item 2, item 3) match any of the individual cells in a column in sheet 3

The following code exposes VBA's Split function for worksheet use--it returns a row array of items that have been split using a specified delimiter. For example, if cell A1 contained the text "Item 1,Item 2"), EXPLODE(A1,",") would return an array with elements "Item 1" and "Item 2".
Function EXPLODE(str As String, Optional delimiter As Variant) As Variant
If IsMissing(delimiter) Then
delimiter = " "
End If
EXPLODE = Split(str, delimiter)
End Function
It is an array function. To use the returned elements in the spreadsheet:
Select the cells in which you want the "exploded" items show
Enter the function specifying the cell with the source string (or reference to the cell which contains the source) and the delimiter on which the split will be done
Complete the entry using the Control-Shift-Enter key combination.
Alternatively, individual elements can be chosen using the INDEX function--=INDEX(EXPLODE(A1,1,2) would return "Item 2" using the previous example. (Given a range or array, the INDEX function returns the value in the ith row and jth column.) This usage does not require the formula to be entered as an array formula.
For your use case, a combination with other functions would be in order. You have a string with multiple items of the form "aa, bb, cc" (the result of a VLOOKUP) and want to determine whether any of the elements of this string can be found as individual items in any of the cells in column A. You want a function that will return True if all of the elements are found, and False otherwise. The following formula achieves that result:
=SUM(SIGN(IFERROR(MATCH(TRIM(EXPLODE(D1,",")),$A:$A,0),0)))=COUNTA(EXPLODE(D1,","))
It is an array formula and needs to be entered with Control-Shift-Enter. Note that I used the contents of cell D1 in lieu of your lookup value. The TRIM function strips out any extraneous spaces between the elements of the string with multiple items.

(not really an answer, just trying to figure out what the question is)
Sheet 1 has a dropdown box with a number of items in, the selected item is used in a vlookup() looking at a table in sheet 2.
Sheet 2 has 2(+) columns, one which is an index used for a vlookup and the other which contains delimited lists.
Sheet 3 has 1(+) columns, each row has a value that may correspond to an item in one of the delimited lists in sheet 2.
When an item is selected in the dropdown box on sheet 1 I want to lookup the corresponding list in sheet 2 (using the vlookup) and then see if any of the items in that list exist in sheet 3.
Is this what your trying to do? If yes, what is the result of this search?
Boolean: True-Some matches found!, False-No Matches
Number: I found this many results
No? :(
Update
Doing that with just worksheet functions would be fairly tricky!
VBA is a much better choice. (the final step atleast)
Add the following code to a new module (not a worksheet or workbook module) and it will be available as a UDF on your worksheets.
This function takes a string (which is your delimited list) it is exploded inside the function so you dont have to worry about doing it.
I've not tested it, but in theory it should allow you to pass it a list. The function then should check sheet 3 for you and return true/false depending on weather the items are found or not.
I know that you've found an answer, but here is a working and slightly faster version of my function.
Public Function ValidateList(ByVal Target As Range) As Boolean
Dim Sheet As Worksheet: Set Sheet = ThisWorkbook.Worksheets("Sheet3") ' Check Sheet3 is the correct sheet
Dim List As Variant: List = Sheet.UsedRange.Columns("A").Value2 ' Set Column(A) to correct column
Dim Items() As String: Items = Split(Target.Value2, ",")
Dim Item As Long
Dim Key As String
Dim Result As Boolean: Result = False
Dim Search As Object: Set Search = CreateObject("Scripting.Dictionary")
For Item = LBound(Items) To UBound(Items)
Search.Add Trim(Items(Item)), False
Next Item
If Search.Count > 0 Then
' Target List has 1+ Items
For Item = LBound(List, 1) To UBound(List, 1)
Key = Trim(List(Item, 1))
If Search.Exists(Key) = True Then
Search.Remove Key
End If
If Search.Count = 0 Then
Result = True
Exit For
End If
Next Item
Else
' Target List is Empty
' Optionally set result to True here if empty list should return True
' Defaults to False
End If
ValidateList = Result
End Function

Related

Calling VBA custom concatenate function in main Sub

I have a set of data as below, where the first row for each Reference number is a summary of all rows below it:
Reference
Date
Comment
Hidden, Concatenated
1
20/6/22
1
20/6/22
Test
20/6: Test
1
18/6/22
Test2
18/6: Test2
2
20/6/22
3
16/6/22
Where the Hidden, Concatenated column is done using the built-in Excel =CONCAT function, as =CONCAT(TEXT([#[Date]],"dd/mm"),": ",[#Comment]).
Also in this, I have a VBA UserForm in which the Reference is selected from a ComboBox, and Comments added in a TextBox. This inserts a new row directly underneath the summary row, with the date of the note entry and the comment populated into this new row.
I have used the UDF provided in https://www.extendoffice.com/documents/excel/2723-excel-concatenate-based-on-criteria.html, which works well, but takes a long time, as this is a long document.
The end aim is for the cell C2 to equal 20/6: Test, 18/6: Test2
I have been using the UDF:
ConcatenateIf(CriteriaRange As Range, Condition As Variant, _
ConcatenateRange As Range, Optional Separator As String = ", ") As Variant
as =ConcatenateIf(A:A,[#[Reference]],D:D) in C2.
I have done a workaround now of limiting the range to A2:A500 and D2:D500, but is it possible to call this function within the sub that inserts the new line? I.e. Not to insert the function as ws.Cells("C2").Formula = "=ConcatenateIf(A:A,[#[Reference]],D:D, but to have the Value of the function inserted?
Thank you in advance.

How to validate dynamic sub list using VBA?

I have an excel file with 2 sheets
In the first one, I have two columns:
In the second, I have an SQL query that loads into Excel that looks something like this:
I have validation on the first column, limiting the value to column A, so the user can either start typing which item he wants, or use the dropdown to pick.
My issue is that I want to create validation on the second column, so that only the options applicable to that Item are available (ex. if the first column is Item 1, only options A, B, and C are available to be selected.) The SQL data is dynamic (possibly different options in Column B for each A), and new items are added and removed. The solutions I saw (ex. https://trumpexcel.com/dependent-drop-down-list-in-excel/) involved creating the two filters on two axis, but I'm not sure how that would work in my situation.
If you can create a list of unique values from the first column to use as the source for the first drop-down (e.g. like in ColD below), you can configure the second drop-down to use a "Source" formula like:
=OFFSET($B$1,MATCH(I2,$A:$A,0)-1,0,COUNTIF($A:$A,I2),1)
Where I2 here is the corresponding drop-down pointed at ColA values (see example screenshot)
Assuming your source data is sorted on ColA.
EDIT: adding a different (perhaps more flexible) approach:
Define a workbook name like "validation" which points to a VBA function which returns a range:
Corresponding function in a regular code module:
Function getOptions() As Range
Dim m As Long, c As Range, v
Set c = Application.Caller 'getOptions is called from the cell
' where the drop-down is clicked
v = c.Offset(0, -1).Value 'read cell (e.g.) to left of the one being filled
'Debug.Print v
If Len(v) > 0 Then
'do the same thing we did with the DV list Source formula above
m = Application.Match(v, c.Parent.Columns("A"), 0)
If Not IsError(m) Then
'return a range (must be contiguous)
Set getOptions = c.Parent.Cells(m, "B").Resize( _
Application.CountIf(c.Parent.Columns("A"), v), 1)
End If
End If
End Function
Finally, set up your cell validation list to point to =validation
The advantage of this approach (despite being a little more set-up and requiring a macro-enabled workbook) is that the VBA in the function can look at the context of the calling cell (via Application.Caller) and decide what range of cells to return to be shown in the drop-down.

excel macro for checking the duplicate entries in coloumn

I looking for a macro which shall find the duplicate entries in the other column.
For example, the spreadsheet I've has more than 300 entries in both column A and B and the values assorted. Now, I need to find out the duplicate entries between the columns. Like westford xxxx there in the column B or not? Please help.
Column A Column B
WestFord xxxx 1.1/2.2 1.50 Direct Link
Direct Link 1.1/2.3 1.55 Westford xxxx
You can use the "Match(Lookup_Value, Lookup_Array, [Match_type])" function. The function returns a number, if the value is found and "N/A" if it is not. First check column B for each element in column A. Then check Column A for each element in Column B.
If the Match function isn't enough, since you have partial matches, you could write a user defined function that identifies whether a value exists in the array. Below is an example of a function that checks the first characters for matching.
Function StartsWith(InputStr As String, InArr As Range, Optional Chars As Integer = 5) As Boolean
Dim i As Integer
Dim compStr As String
Dim foundFlag As Boolean
For i = 1 To InArr.Rows.Count
If Len(InputStr) > Chars Then 'we check to make sure inputstr isn't longer
compStr = Left(InputStr, Chars) 'than then the number of characters we need
Else
compStr = InputStr 'if it is too long, then compare the whole thing
End If
If compStr = Left(InArr(i, 1), Len(compStr)) Then
foundFlag = True
Exit For
End If
Next i
StartsWith = foundFlag
End Function
If this code in a module in an open spreadsheet, you can use StartsWith like any other function. If you want further automation (like deleting the cells if a duplicate is found, you can write a sub to do that also!
The internet is FULL of VBA tutorials like this one.
Try a Google Search

Put unique distinct values into a list from multiple columns of an array

I'm new to Excel and the journey has been good so far, but I haven't been able to resolve this particular issue by myself. I'm dealing with a table as under:
Essentially, I'm looking to refer to the array of tags in columns from B3:E6, and do the following:
Create a "Unique Tags" column: Create a unique list of "tags" in column H by removing duplicates.
Create a "Maximum Marks" column: Look for each of the unique tags in the array in each row, and return the marks from the marks column in the same row. If the tag appears in multiple rows. the sum of the corresponding marks in these multiple rows should be returned in the maximum marks column in column I. For example, 'EASY' appears in E3 as well as E5. Thus in the 'Unique Tags' List 'EASY' should correspond to Maximum Marks = 4 (2+2).
I could do this manually using formulas such as SUMIF, but I'm looking for a way to automate it since I might have to do this operation for a similar dataset with additional rows & columns. I'm open to VBA solutions as well but would prefer some sort of formula.
I hope I've explained it well enough! Thanks and looking forward to your inputs.
One way to do this is create a function that returns the array of your unique cells and then multiplies them all by matches in your Marks column.
Create the unique cells with this array function. Note this function uses the Dictionary object. In the VB Editor, go to Tools > References, and make sure Microsoft Scripting Runtime is selected.
Public Function UniqueValues(aRange As Range)
Dim DictValues As New Dictionary
Dim cll As Variant
Dim aryResults() As String
For Each cll In aRange
If Not DictValues.Exists(cll.Value) Then DictValues.Add cll.Value, "":
Next
UniqueValues = DictValues.Keys
Set DictValues = Nothing
End Function
Enter in cell H3 and press CTRL SHIFT RETURN (as it's an array function)
=TRANSPOSE(uniquevalues(B3:E6))
and drag down to H15 or beyond
We have to use TRANSPOSE as the array comes out in a row from the function.
Next we need to find the matching cells and multiply. Here in C15 enter the formula below
=INDEX(SUM((($B$3:$E$6=H3)*1)*$F$3:$F$6),1)
Drag this down to H15.

Excel conditional formatting for the entire row with more than one formula

After 3 hours of searching I still didn't find an answer, here is what I am trying to do:
I am trying to fill with green any row that has WBS in it and with Red any row that has ACT in it and Blue any row that has EPR in it. It works for the first formula then when I try to add the second one every thing get messed up.
what i have understood is that you need to search a keyword in a row and if its found in any cell of that row then color it.
May be we can do it with conditional formatting but i have another idea. We can create a simple search function in Excel VBA. Something like this:
=search_row(A1:F1,"EPR")
The function will return 1 if EPR is found in any cell of specified row. Now if you create two different columns at the end of data columns, name first with WPS and second with EPR and write this function in it. Like
G1 =search_row(A1:F1,"WPS")
H1 =search_row(A1:F1,"EPR")
Drag it to end. Now sort the columns. First for WPS from higher to lower. Then color all rows having 1 in a single select. Similarly do the same with EPR (H1) column.
To use this function you can download the macro file from the following URL:
http://asimishaq.com/myfiles/SearchHighlight.xlsm
Now to run it first of all enable macros, and then re-open your data file and then open this macro file. As long as this macro file is opened you can use this function. Following is the VBA code if you want to create the macro yourself:
Function search_row(sRow As Range, Keyword As String)
Dim i As Integer
Dim Found As Integer
For i = 1 To sRow.Columns.Count
If InStr(1, LCase(sRow.Cells(1, i)), LCase(Keyword)) > 0 Then
search_row = 1
End If
Next
End Function
I had a go at making a function similar to asim-ishaq to determine if your search term exists in the row for fun :) then tried to apply it to highlighting rows, turns out I dont know how to use conditional formatting very well! Figured it out in the end, hopefully I've explained it well enough.
With this you will have to have (one) extra column at the end of your data to contain the result.
It might be possible to not require the extra column by putting the function inside the conditional formatting, however I couldn't get it to work (didn't try very hard). This isn't a great loss as it's much simpler to edit the formula if its on the workbook, instead of having to go through each conditional rule to edit it, should you need to edit it in the future.
To get the formatting to work you will need to create a number of rules (one per keyword)
You want to create a rule of the type shown below, in the formula box you need something along the lines of: =INDIRECT("D" & ROW())=0 where D is the column containing the result of the function below and 0 is the index of the keyword you're highlighting.
In my example, the formula in the D Column is: =SearchRow(An:Cn,"ABS","KBS","JBS") (where n is the row the formula is on)
Set the formatting as desired then press OK, when you return to the rule manager you will need to update the Applies to value, which should be a range that covers all the data you want to highlight. In my example it was $A$1:$C$3
My function below takes 2+ Arguments, The first is the range to search. The second (and any subsequent ones) are search terms.
The function will return a number. -1 for no matches and 0+ for the found search term. The number depends on the position in the arguments.
A1 = "ABS"
B1 = "SBA"
A2 = "SBA"
B2 = "ABS"
A3 = ""
B3 = ""
C1 = "=SearchRow(A1:B1, "ABS", "SBA")"
C2 = "=SearchRow(A2:B2, "ABS", "SBA")"
C3 = "=SearchRow(A3:B3, "ABS", "SBA")"
C1 > 0
C2 > 1
C3 > -1
The function will always return the first result, searching left to right comparing each cell to the Keywords in order. Using my example, if a cell contained "SBA ABS" the result would be 0 (for ABS). I guess your cells will probably only contain one keyword though so this shouldn't be a problem?
Public Function SearchRow(ByVal Row As Range, ParamArray Keyword() As Variant) As Integer
Dim Column As Integer
Dim Value As String
Dim Index As Integer
Dim Result As Integer
For Column = 1 To Row.Columns.Count
Value = LCase(Row.Cells(1, Column))
Result = -1
For Index = LBound(Keyword) To UBound(Keyword)
If InStr(1, Value, LCase(Keyword(Index))) > 0 Then
Result = Index
Exit For
End If
Next Index
If Result > -1 Then
Exit For
End If
Next Column
SearchRow = Result
End Function

Resources