paste values if cells match - excel

In the previous post you guys helped me to find out a solution in order to copy-paste cells.
By now I've got a slight different problem.
Here is it; I've got 2 different sheets;
worksheets("Food")
Worksheets("Numbers")
In worksheets("Food"), I've got the following board;
| Fruits | Vegetables |
| -------- | --------------|
| Banana | Carrots |
| Peach | Spinachs |
| Pineapple | Cauliflowers |
In worksheets("Numbers"), I've got this;
| Fruits | Numbers |
| -------- | --------- |
| Banana | 9 |
| Apple | 2 |
| Orange | 3 |
| Peach | 7 |
| Pineapple | 5 |
I'd like to search for each fruits from worksheets("Food") if they do exist in worksheets("Numbers"). If yes, then automatically insert a new column in worksheets("Food") between column Fruits and Vegetables named "Numbers".
After, picked up numbers beside each found fruits in worksheets("Numbers") and paste it in worksheets("Food") beside the matching fruit in the new created column.
Like this;
| Fruits |*Numbers* |Vegetables
| -------- |-------------- |------------
| Banana |**9** |Carrots
| Peach |**7** |Spinachs
| Pineapple |**5** |Cauliflowers
I've been trying to run a code doing this process but as I run it nothing happens ( no error occurs neither)...
Here is it;
Sub Add_Fruits_Numbers()
Dim lastlineFood As Long
Dim lastlineRef As Long
Dim j, i, compteur As Integer
Dim x As Long, rng As range
lastlineRef = Worksheets("Numbers").range("A" & rows.Count).End(xlUp).row
For j = 1 To lastlineRef
lastlineFood = Worksheets("Food").range("A" & rows.Count).End(xlUp).row
For i = 1 To lastlineFood
If range("A" & i).Value = Worksheets("Numbers").range("A" & j).Value Then
Set rng = Worksheets("Numbers").range("A1", range("A1").End(xlToRight))
For Each cell In rng
If cell.Value = "Fruits" Then
cell.EntireColumn.Offset(0, 1).Insert (xlShiftToRight)
End If
Next cell
Worksheets("Food").range("A" & i).Offset(, 1).Value = Worksheets("Numbers").range("A" & j).Offset(, 1)
End If
Next i
Next j
End Sub
I'd heavily appreciate your help once again, thank you !

Your code has some problems. It should raise an error on the line
Set rng = Worksheets("Numbers").range("A1", range("A1").End(xlToRight))
if the active sheet is not "Numbers". range("A1").End(xlToRight) refers the active sheet. The correct code should be:
Set rng = Worksheets("Numbers").range("A1", Worksheets("Numbers").range("A1").End(xlToRight))
Then, your code inserts a column in the "Numbers" sheet.
You should use Range("B" & i).EntireColumn.Insert instead of cell.EntireColumn.Offset(0, 1).Insert (xlShiftToRight). cell belongs to the range in "Numbers" sheet.
The code logic is wrong. The above sequence must be run only once. Otherwise it will insert a column for each match. "Fruits" will be there of each iteration.
Then everything is messed up and debugging more has no sense, no offence...
It is easier to show you a simpler/faster code, doing what (I understood) you want.
Please, try the next code:
Sub bringFruitsNo()
Dim shF As Worksheet, shN As Worksheet, lastRF As Long, lastRN As Long
Dim arrF, rngN As Range, mtch, i As Long, boolOK
Set shF = Sheets("Food")
Set shN = Sheets("Numbers")
lastRF = shF.Range("A" & shF.rows.count).End(xlUp).row 'last row
lastRN = shN.Range("A" & shN.rows.count).End(xlUp).row 'last row
If shF.Range("B1").value = "Numbers" Then boolOK = True 'check if the column has already been inserted in a previous run
arrF = shF.Range("A2:A" & lastRF).value 'put the first column in an array (for a faster iteration)
Set rngN = shN.Range("A2:A" & lastRN) 'set the range where to search for the fruit existence
For i = 1 To UBound(arrF) 'iterate between the array elements:
mtch = Application.match(arrF(i, 1), rngN, 0) 'if the fruit has bee found:
If IsNumeric(mtch) Then
'insert the new necessary column and mark the inserting event changing the boolean variable value
If Not boolOK Then shF.Range("B1").EntireColumn.Insert: shF.Range("B1").value = "Numbers": boolOK = True
shF.Range("B" & i + 1) = shN.Range("B" & mtch + 1).value 'Place the number in the new column
End If
Next i
End Sub
But, I think you maybe will need to use this code after the column has been inserted, and the code is checking if between "Fruits" and "Vegetables" a column named "Numbers" exists...
If not necessary, and always the code must insert a column between the first and the third column, that line can be deleted.

Related

Excel VBA: vlookup to find row of date in date range table

Hi and thanks in advance for any help. Extracting daily files that have the date in a cell. I need to use the date to find which week it falls into in a table which has start and end dates in two columns. There is more data in subsequent columns I need to extract once I know the row the date falls into. The cross reference table is in this format: The date variable (assigned to both string and date variables) that is picked up from the source needs to be compared to col's A and B to find out what row it would fit in then extract fiscal year (Col A) as well as short description (col F)
Cross Ref Table
The adjusted and renamed destination file looks like this
The functionality described here can be accomplished via cell formulas without resorting a VBA function. I included 2 possible solutions.
I have simplified the scenario a bit. Assume that the cross reference table (located in Sheet1 of a XR.xlsx file) only contains these 3 columns:
A B C
+--------------+---------------+---------------+
1 | PDWK_St_Date | PDWK_End_Date | Short_Descrip |
+--------------+---------------+---------------+
2 | 07-Nov-16 | 13-Nov-16 | P1W1 |
3 | 14-Nov-16 | 20-Nov-16 | P1W2 |
4 | 21-Nov-16 | 27-Nov-16 | P1W3 |
5 | 28-Nov-16 | 04-Dec-16 | P1W4 |
6 | 05-Dec-16 | 11-Dec-16 | P2W1 |
7 | 12-Dec-16 | 18-Dec-16 | P2W2 |
8 | 19-Dec-16 | 25-Dec-16 | P2W3 |
9 | 26-Dec-16 | 01-Jan-17 | P2W4 |
10 | 02-Jan-17 | 08-Jan-17 | P3W1 |
11 | 09-Jan-17 | 15-Jan-17 | P3W2 |
12 | 16-Jan-17 | 22-Jan-17 | P3W3 |
13 | 23-Jan-17 | 29-Jan-17 | P3W4 |
14 | 30-Jan-17 | 05-Feb-17 | P4W1 |
15 | 06-Feb-17 | 12-Feb-17 | P4W2 |
16 | 13-Feb-17 | 19-Feb-17 | P4W3 |
17 | 20-Feb-17 | 26-Feb-17 | P4W4 |
18 | 27-Feb-17 | 05-Mar-17 | P5W1 |
+--------------+---------------+---------------+
Solution 1 (simplified)
It only works if the date ranges are consecutive (i.e. start date = end date from previous row + 1 day) - his is the case in your cross reference table.
In your destination workbook, use VLOOKUP to refer to the cross reference table:
=VLOOKUP(B2,[XR.xlsx]Sheet1!$A$2:$C$18,3,TRUE)
The above formula is specific to row 2 in the destination table and assumes the "Business Date" is in column B (hence B2 in the 1st parameter), 2nd parameter is the lookup range, 3 in the 3rd parameter means the value to retrieve is in the 3rd column and TRUE allows date matching within a range (from start date to the next row's start date).
Note that the formula can be easily replicated to other rows, e.g. by dragging the fill handle (the small square in the cell's bottom-right corner).
Solution 2
In this approach, the business date is compared against both start and end dates from the cross-reference table. Instead of VLOOKUP, it uses INDEX and MATCH functions:
=INDEX([XR.xlsx]Sheet1!$C$2:$C$18,MATCH(1,(B2>=[XR.xlsx]Sheet1!$A$2:$A$18)*(B2<=[XR.xlsx]Sheet1!$B$2:$B$18),0),1)
Here, the business date (cell B2) is compared against both start and end date, the results are multiplied (equivalent to logical AND) and matched against 1 (i.e. TRUE).
IMPORTANT: After pasting this formula (e.g. into formula bar for cell C2) you need to hit Ctrl+Shift+Enter instead of the usual Enter. This is to indicate a so-called "array formula" (aka CSE formula); otherwise, our comparisons inside MATCH wouldn't work as intended. You may refer to this post for more info. The CSE formulas show surrounded by braces in the formula bar. The good news is that they can be replicated just like all other formulas.
The destination table will look similar to:
A B C
+------+---------------+-------------+
1 | Unit | Business Date | Short Descr |
+------+---------------+-------------+
2 | 1102 | 26-Aug-17 | #N/A |
3 | 1102 | 05-Jan-17 | P3W1 |
4 | 1102 | 06-Feb-17 | P4W2 |
5 | 1102 | 11-Nov-16 | P1W1 |
6 | 1102 | 02-Feb-17 | P4W1 |
7 | 1102 | 01-Oct-16 | #N/A |
+------+---------------+-------------+
Note that in case of solution 1, cell C2 would contain P5W1 instead of #N/A - this is because no end date was used in comparison.
The Function Provided by #PGTester worked great once a couple of issues were dealt with in the code:
1) Declarations: The declarations were all on one line for each type. This does not work in VBA as only the last variable is declared as intended and all previous ones are declared as variant. (ie, DIM adate, bdate, cdate as date) In this example only cdate is an actual date. Passing adate to the function resulted in a mismatch until the declarations were corrected. (This was pointed out by #Domenic)
2) Date formats: While all dates in the source file and the cross reference file were formatted as "yyyy-mmm-dd" prior to calling the function, Error 13, Type Mismatch still prevented the code from moving forward. Changing the format to "m-d-yyyy" on both the source file (done in code) and the cross reference table (manually prior to accessing) solved the issue and the following code worked as expected.
3) Pointing the function calls at the cross reference file for both the vlookup and rnglookup was done by building and setting variables to the pages needed. This simplified the selections when required.
Set variables for next steps
'
Set CRef = Workbooks.Open(refFILE)
Set shtJOB = CRef.Sheets("JobCross")
Set shtDATE = CRef.Sheets("fcalendar")
sht.Activate
Set rngJOBS = Range("i2:i" & lastRow)
Set rngJBGRP = shtJOB.Range("A1:b16")
Set rng = shtDATE.Range("A2:f210")
Completed code with both functions follows:
Sub CleanDaily_Labour()
'
' CleanDaily_Labour Macro
' RMDC Payroll Resarch (MU) Report prep
'
' Note the separate declarations for each variable
'
Dim myPath As String, fName As String, refFILE As String, job As String, _
JobGR As String, DateST As String, WKDay As String, PDWK As String
Dim CRef As Workbook, wkb As Workbook
Dim shtDATE As Worksheet, shtJOB As Worksheet, sht As Worksheet
Dim aDate As Date, fYR As Date
Dim fYear As Variant
Dim rng As Range, rngJOBS As Range, rngJBGRP As Range
Dim SC As Long, lastRow As Long, PD As Long, WK As Long
' Application.ScreenUpdating = False
myPath = Application.ActiveWorkbook.Path
'
' Get the file date and assign to variables
'
Range("D3").Select
**Selection.NumberFormat = "m-d-yyyy"**
aDate = Range("D3").Value
DateST = WorksheetFunction.Text(aDate, "YYYYMMDD")
WKDay = WorksheetFunction.Text(aDate, "DDD")
Selection.Copy
Range("D7").Select
ActiveSheet.Paste
'
' Rename and save the active workbook by date
' set wkb to new workbook name and assign calendar cross ref
'
fName = myPath & "\Daily_Labour_" _
& DateST & ".xlsx"
ActiveWorkbook.SaveAs fName, 51
Set wkb = Workbooks.Open(fName)
Set sht = wkb.Sheets("Sheet1")
refFILE = myPath & "\Cross_Ref_fCalendar.xlsx"
'
' Remove extra header info
'
Rows("1:5").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
'
' Insert Column to the left of Column D
'
Columns("E:G").Insert Shift:=xlToRight, _
CopyOrigin:=xlFormatFromRightOrBelow
'
' Update Headers that will be kept / used
'
Range("A1").Value = "FYear"
Range("E1").Value = "PD_WK"
Range("J1").Value = "JOB_GRP"
Range("F1").Value = "WKDay"
Range("G1").Value = "PD"
Range("H1").Value = "WK"
'
Rows("1:1").Select
With Selection
.HorizontalAlignment = xlCenter
End With
'
' Remove extra columns
'
Sheets("Sheet1").Range("K:K,M:P,R:AY").EntireColumn.Delete
'
' Get the last row and fill known columns
'
lastRow = Cells(Rows.Count, 1).End(xlUp).row
Range("d2:d" & lastRow).Value = aDate
Range("d2:d" & lastRow).NumberFormat = "m-d-yyyy"
Range("f2:f" & lastRow).Value = WKDay
'
' Set variables for next steps
'
Set CRef = Workbooks.Open(refFILE)
Set shtJOB = CRef.Sheets("JobCross")
Set shtDATE = CRef.Sheets("fcalendar")
sht.Activate
Set rngJOBS = Range("i2:i" & lastRow)
Set rngJBGRP = shtJOB.Range("A1:b16")
Set rng = shtDATE.Range("A2:f210")
'
' Loop through jobs in column i match job in shtJOB
' put matching group in row j (Use Function vLookupVBA)
'
For Each jRow In rngJOBS
jRow.Select
job = ActiveCell.Value
JobGR = VLookupVBA(job, rngJBGRP, Null)
ActiveCell.Offset(0, 1).Value = JobGR
'end for
Next jRow
'
'Save Progress during testing:
'
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs fName, 51
'
' Fill in date parameters from Cross Ref file for Business date
' Use function rngLOOKUP to update variables then set ranges to the variables
' May be more efficient to get row number from cross ref table instead - later.
'
shtDATE.Activate '(does not seem to affect)
'
fYear = rngLOOKUP(aDate, rng, 3)
PDWK = rngLOOKUP(aDate, rng, 6)
PD = rngLOOKUP(aDate, rng, 4)
WK = rngLOOKUP(aDate, rng, 5)
'
' Fill the columns with the variables (can likely bypass the variables and put on 1 line)- later
'
sht.Activate
Range("A2:A" & lastRow).Value = fYear
Range("E2:E" & lastRow).Value = PDWK
Range("G2:G" & lastRow).Value = PD
Range("H2:H" & lastRow).Value = WK
'
' Close reference file
'
Application.DisplayAlerts = False
CRef.Close False
'
' Cleanup, save and close workbooks
'
Application.DisplayAlerts = False
wkb.SaveAs fName, 51
'
' SQL call: Load to existing datbase (GDrive), use same format as Transactions
' ?? Get sales by day? vs maintain PDWK - Future
'
Application.DisplayAlerts = True
Application.ScreenUpdating = True
' wkb.Close.false
End Sub
Private Function VLookupVBA(what As Variant, lookupRng As Range, defaultValue As Variant) As Variant
Dim rv As Variant: rv = Application.VLookup(what, lookupRng, lookupRng.Columns.Count, False)
If IsError(rv) Then
VLookupVBA = "NULL"
Else
VLookupVBA = rv
End If
End Function
Public Sub UsageExample()
MsgBox VLookupVBA("ValueToFind", ThisWorkbook.Sheets("ReferenceSheet").Range("A:D"), "Not found!")
End Sub
Function rngLOOKUP(chkDate As Date, rngf As Range, theColumn As Long) As Variant
Dim acell As Range
'
For Each acell In rngf.Columns(1).Cells
If acell.Value <= chkDate And acell.Offset(0, 1).Value >= chkDate Then
rngLOOKUP = acell.Offset(0, theColumn - 1).Value
Exit Function
End If
Next acell
rngLOOKUP = "#Nothing"
End Function
This custom function is similar to Vlookup where it will compare the first two columns of a range as a date, and if the input date falls in the range, it will return the respective column.
Function rngLOOKUP(aDate As Date, rng As Range, theColumn As Long) As Variant
Dim acell As Range
For Each acell In rng.Columns(1).Cells
If acell.Value <= aDate And acell.Offset(0, 1).Value >= aDate Then
rngLOOKUP = acell.Offset(0, theColumn - 1).Value
Exit Function
End If
Next acell
rngLOOKUP = "#Nothing"
End Function
In this excel file, you can see it in action. Or see below screenshot. The highlight cell has the custom formula.

How to remove all duplicates from a column in excel using VBA only leaving rows that have no duplicate?

I'm trying to delete all duplicate values from a column of numbers in Excel. I want the remaining column to only contain unique values from the original table.
I have tried using the RemoveDuplicates method but it only removes a single instance of a duplicate instead of all of them.
I have also tried using the following code but it has the same problem as RemoveDuplicates. I'm not sure why though since the "Unique" tag is set to "True".
{MYWORKSHEET]AdvancedFilter Action:= _
xlFilterCopy, CopyToRange:=[MYWORKSHEET].Range("B1"), Unique:=True
I have only found one solution that should work theoretically that uses a nested For loop to iterate over every individual row and check if it is equivalent to any other row in the table. The only problem is that this crashes Excel on my machine because it has to loop so much. Is there any way to do this other than this brute force method?
Here is what I'm looking for:
|-------| |----------------| |-------------------|
| INPUT | | DESIRED OUTPUT | | WHAT I DONT WANT |
|-------| |----------------| |-------------------|
| 11111 | | 11111 | | 11111 |
|-------| |----------------| |-------------------|
| 22222 | | 55555 | | 22222 |
|-------| |----------------| |-------------------|
| 33333 | | 33333 |
|-------| |-------------------|
| 22222 | | 55555 |
|-------| |-------------------|
| 33333 |
|-------|
| 55555 |
|-------|
Use the Advanced Filter with a formula criteria of, for example: =COUNTIF($A$6:$A$11,A6)=1
Result:
If you need to use a formula instead, you can do something like:
=IFERROR(INDEX(inputTbl,AGGREGATE(15,6,1/(COUNTIF(inputTbl[Input],inputTbl[Input])=1) * ROW(inputTbl)-ROW(inputTbl[#Headers]),ROWS($1:1))),"")
You can load the values into a dictionary and set the value of the key to false, check if the key exists and if so change the value to true. Iterate through the dictionary and only dump keys that are false.
dim mydict as object
dim iter as long
dim lastrow as long
dim cellval as string
dim dictkey as variant
set mydict = createobject("Scripting.Dictionary")
with activesheet
lastrow = .Cells(.Rows.Count, "ColumnLetter").End(xlUp).row
for iter = 1 to lastrow
cellval = .cells(iter, "ColumnLetter").value
if not mydict.exists(cellval) then
mydict.add cellval, False
else
mydict(cellval) = True
end if
next
iter = 1
for each dictkey in mydict
if mydict(dictkey) = False then
.cells(iter, "ColumnLetter").value = dictkey
iter = iter + 1
end if
next
end with
Well, here's a macro to actually do the deletions, or at least get you started:
Private Sub CommandButton1_Click()
Dim celll, rng As Range
Dim strRow, strRowList As String
Dim strRows() As String
Set rng = Range("a1:a" & Range("a1").End(xlDown).Row)
For Each celll In rng
If celll.Address = rng(1, 1).Address Then
If celll.Value = celll.Offset(1, 0).Value Then strRow = celll.Row
ElseIf celll.Value = celll.Offset(-1, 0).Value Or celll.Value = celll.Offset(1, 0).Value Then
strRow = celll.Row
End If
If strRowList = "" Then
strRowList = strRow
ElseIf strRow <> "" Then
strRowList = strRowList & "," & strRow
End If
strRow = ""
Next
MsgBox (strRowList)
strRows() = Split(strRowList, ",")
For i = UBound(strRows) To 0 Step -1
Rows(strRows(i)).Delete
Next
End Sub

Split a delimited list based on variable ending characters into specific columns

I have managed to get to a point with a data set where i have a list of items delimited with a "|" symbol. I am now trying to separate each item in the list into the corresponding column, however the identifier of the column is a bit of text at the end of each value of variable length.
Example Data (all in one column):
Column A
40.00A|24.00QS|8.00J[a]
40.00A|12.00J|8.00J[a]
20.00A|4.00V
30.00A|12.00CS|8.00QS
Desired Outcome:
+-------+-------+------+-------+-------+------+
| A | QS | J[a] | J | CS | V |
+-------+-------+------+-------+-------+------+
| 40.00 | 23.00 | 8.00 | | | |
| 40.00 | | 8.00 | 12.00 | | |
| 20.00 | | | | | 4.00 |
| 30.00 | 8.00 | | | 12.00 | |
+-------+-------+------+-------+-------+------+
The number of trailing characters that define columns is fixed to 6 (A,QS,J[a],J,CS & V), so I know at the beginning how many columns I will need.
I have some ideas on how to do it directly through formulas, but it would require me to split out the items into individual columns by the delimiter, then use some sort of if statement on some additional columns. Would prefer to avoid the helper column issue. Also, looked at the following link, but it doesn't solve the solution, as it assumes the value matches the column heading (I can correct that, but I feel like there is a faster VBA solution here):
How to split single column (with unequal values) to multiple columns sorted according to values from the original single column?
I have been reading about Regular Expressions, and i suspect there is a solution there, but I can't quite figure out how to sort the result.
Once i have this data setup, it is a small task to unpivot it and get the data in a proper tabular format using Power Query.
Thanks in advance!
since headers are fixed, it can simply be tried out like this (the Row & Column of the Source & destination data may be changed to your requirement)
Option Explicit
Sub test()
Dim Ws As Worksheet, SrcLastrow As Long, TrgRow As Long, Rw As Long
Dim Headers As Variant, xLine As Variant
Dim i As Long, j As Long
Set Ws = ThisWorkbook.ActiveSheet
'Column A assumed to have the texts
SrcLastrow = Ws.Range("A" & Rows.Count).End(xlUp).Row
TrgRow = 2
Headers = Array("A", "QS", "J[a]", "J", "CS", "V")
For Rw = 1 To SrcLastrow
xLine = Split(Ws.Cells(Rw, 1).Value, "|")
For i = 0 To UBound(xLine)
For j = 0 To UBound(Headers)
xLine(i) = Trim(xLine(i))
If Right(xLine(i), Len(Headers(j))) = Headers(j) Then
Ws.Range("D" & TrgRow).Offset(0, j).Value = Replace(xLine(i), Headers(j), "") ' The output data table was assumed to be at Column D
End If
Next j
Next i
TrgRow = TrgRow + 1
Next
End Sub

Transforming multiple rows to one row

I have a text data set that I need to reformat before I can use it. It's currently a text file that I've imported into Excel. Each record currently spans three rows but is in one column. I need to transform it so it's one row with three columns.
The sample below is how my data is currently structured. It shows three records out of 2,000+. The 'Row' column is just for reference and not actually in my data.
Row | Column
1 | File Number: 001
2 | File Code: ABC
3 | File Description: Text file
4 | File Number: 002
5 | File Code: DEF
6 | File Description: Text file
7 | File Number: 003
8 | File Code: GHI
9 | File Description: Text file
Just to clarify, row 1 to 3 would be one record. Row 4 to 6 would be the second record. The third record is from row 7 to 9. Every record in my data is currently split into three rows.
I want to reformat it so it looks something like this:
Row | File Number | File Code | File Description
1 | 001 | ABC | Text
2 | 002 | DEF | Text
3 | 003 | GHI | Text
Again, the row column is just for reference and I don't need it in my reformatted data. Copy and pasting does not appear to be a good option.
Is there a quick way to transform this?
You can use VBA to do this. Code like this might help you for this particular situation.
Option Explicit
Sub Test()
' Let's make the tabular structure in column C, D and E
' C D E
' File Number Code Description
Dim CurrentRow As Integer
CurrentRow = 2 ' Read from A2
Dim WriteRow As Integer
WriteRow = 2 ' Write to C2
Do
' if we see empty data in column A, then we are done with our work
If Len(Trim(Range("A" & CurrentRow))) = 0 Then Exit Do
' make 3 rows of data into 3 columns in a single row
Range("C" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow).Text, "File Number:", ""))
Range("D" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow + 1).Text, "File Code:", ""))
Range("E" & WriteRow).Value = Trim(Replace(Range("A" & CurrentRow + 2).Text, "File Description:", ""))
' increment our reading and writing markers
CurrentRow = CurrentRow + 3
WriteRow = WriteRow + 1
Loop
End Sub
Feel free to test out.
As a reference: this uses TextToColumns, AutoFilter, and places results on a new sheet
Option Explicit
Sub mergeRows()
Dim ws As Worksheet, fld As Variant, i As Long, cel As Range
fld = Split("File Number,File Code,File Description", ",")
Worksheets.Add After:=Worksheets(Worksheets.Count)
Set ws = Worksheets(Worksheets.Count)
Application.ScreenUpdating = False
With Worksheets(1)
Set cel = .Range("A1")
.UsedRange.Columns(1).TextToColumns Destination:=cel.Cells(1, 2), _
DataType:=xlDelimited, _
Other:=True, OtherChar:=":"
.Rows(1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
cel.Cells(0, 2) = "Col 1": cel.Cells(0, 3) = "Col 2"
.UsedRange.AutoFilter
For i = 0 To 2
.UsedRange.AutoFilter Field:=cel.Cells(1, 2).Column, Criteria1:=fld(i)
.UsedRange.Columns(cel.Cells(1, 3).Column).Copy ws.Cells(1, i + 1)
ws.Cells(1, i + 1) = fld(i)
Next
.UsedRange.AutoFilter
.UsedRange.Offset(, 1).EntireColumn.Delete
cel.Cells(0, 2).EntireRow.Delete
End With
ws.UsedRange.Columns.AutoFit
Application.ScreenUpdating = True
End Sub

Excel - All unique words in a range

Perhaps I'm trying to do too much, but I have a column filled with text. Each cell has an arbitrary number of words, so for example:
| A |
=====|====================|
1 | apple pear yes cat |
2 | apple cat dog |
3 | pear orange |
What I need to do is create a column which is a list of all unique words in that range. So for the above example, the result should be:
| A | B |
=====|====================|========|
1 | apple pear yes cat | apple |
2 | apple cat dog | pear |
3 | pear orange | yes |
4 | | cat |
5 | | dog |
6 | | orange |
In no particular order. Is there any way to do this?
This option uses 1 loop instead of 3, I like to use a dictionary instead or Collection.
Sub Sample()
Dim varValues As Variant
Dim strAllValues As String
Dim i As Long
Dim d As Object
'Create empty Dictionary
Set d = CreateObject("Scripting.Dictionary")
'Create String With all possible Values
strAllValues = Join(Application.Transpose(Range("A1", Range("A" & Rows.Count).End(xlUp))), " ")
'Split All Values by space into array
varValues = Split(strAllValues, " ")
'Fill dictionary with all values (this filters out duplicates)
For i = LBound(varValues) To UBound(varValues)
d(varValues(i)) = 1
Next i
'Write All The values back to your worksheet
Range("B1:B" & d.Count) = Application.Transpose(d.Keys)
End Sub
Give this small macro a try:
Sub dural()
Dim N As Long, U As Long, L As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
Dim st As String
For I = 1 To N
st = st & " " & Cells(I, 1)
Next I
st = Application.WorksheetFunction.Trim(st)
ary = Split(st, " ")
U = UBound(ary)
L = LBound(ary)
Dim c As Collection
Set c = New Collection
On Error Resume Next
For I = L To U
c.Add ary(I), CStr(ary(I))
Next I
For I = 1 To c.Count
Cells(I, 2).Value = c.Item(I)
Next I
End Sub

Resources