I am running VBA to search for differences in values in rows between column D and column G. My code works for the first try, but when I add more values towards the end (that are not the same values), the code doesn't seem to follow.
Option Explicit
Public Sub RateTest1()
Const COLUMN_1 = "D", WS1_START = 2
Const COLUMN_2 = "G", WS2_START = 2
Dim ws1 As Worksheet, ws2 As Worksheet, col1 As Variant, col2 As Variant, tr As Long
Dim max1 As Long, max2 As Long, r1 As Long, r2 As Long, red As Long, found As Boolean
Dim miss As Range
tr = Rows.Count: red = RGB(255, 0, 0)
Set ws1 = ThisWorkbook.Sheets("Sheet1"): max1 = ws1.Cells(tr, COLUMN_1).End(xlUp).Row
Set ws2 = ThisWorkbook.Sheets("Sheet1"): max2 = ws2.Cells(tr, COLUMN_2).End(xlUp).Row
col1 = ws1.Range(ws1.Cells(1, COLUMN_1), ws1.Cells(max1, COLUMN_1))
col2 = ws2.Range(ws2.Cells(1, COLUMN_2), ws2.Cells(max2, COLUMN_2))
For r2 = WS2_START To max2
For r1 = WS1_START To max1
If Len(col1(r1, 1)) > 0 And col1(r1, 1) <> "N/A" Then
found = (col1(r1, 1) = col2(r2, 1))
If found Then Exit For
End If
Next
If Not found Then
If miss Is Nothing Then
Set miss = ws2.Cells(r2, COLUMN_2)
Else
Set miss = Union(miss, ws2.Cells(r2, COLUMN_2))
End If
End If
Next
miss.Interior.Color = red
For r2 = WS2_START To max2
For r1 = WS1_START To max1
If Len(col2(r2, 1)) > 0 And col1(r2, 1) <> "N/A" Then
found = (col1(r2, 1) = col2(r1, 1))
If found Then Exit For
End If
Next
If Not found Then
If miss Is Nothing Then
Set miss = ws2.Cells(r2, COLUMN_2)
Else
Set miss = Union(miss, ws2.Cells(r2, COLUMN_2))
End If
End If
Next
miss.Interior.Color = red
End Sub
The codes sometimes only recognizes that column D and G are different if the value in D is greater than G and hardly ever the other way around. The "N/A" code is there because eventually I want to add code that does not highlight if column D has a 1 and column G has an "N/A". Those are considered the same values.
The 2 procedures will find differences (non-empty values) between the two columns, with the exception of value "1" in column D, and value "N/A" in column G
Option Explicit
Public Sub RateTest()
Dim ws As Worksheet, miss As Range, tmp As Range, t As Double
Dim max1 As Long, max2 As Long, colD As Range, colG As Range
t = Timer
Set ws = ThisWorkbook.Sheets("Sheet1")
max1 = ws.Cells(Rows.Count, "D").End(xlUp).Row
max2 = ws.Cells(Rows.Count, "G").End(xlUp).Row
Set colD = ws.Range(ws.Cells(2, "D"), ws.Cells(max1, "D"))
Set colG = ws.Range(ws.Cells(2, "G"), ws.Cells(max2, "G"))
colD.Interior.ColorIndex = xlColorIndexNone
colG.Interior.ColorIndex = xlColorIndexNone
Set miss = CheckColumns(colD, colG, "N/A")
If miss Is Nothing Then
Set miss = CheckColumns(colG, colD, "1")
Else
Set tmp = CheckColumns(colG, colD, "1")
If Not tmp Is Nothing Then Set miss = Union(miss, tmp)
End If
If Not miss Is Nothing Then miss.Interior.Color = RGB(255, 0, 0)
Debug.Print "Rows: " & max1 & "; Time: " & Format(Timer - t, "0.000") & " sec"
End Sub
Private Function CheckColumns(col1 As Range, col2 As Range, x As String) As Range
Dim c As Variant, r As Long, d As Object, rng As Range
col1.NumberFormat = "#,##0.00###"
c = col1.Value2
Set d = CreateObject("Scripting.dictionary")
For r = 1 To UBound(c)
With col1.Cells(r)
If .Errors.Item(xlNumberAsText).Value Then .Value2 = .Value2 + 0
End With
d(Trim$(CStr(c(r, 1)))) = vbNullString
Next
c = col2.Value2
For r = 1 To UBound(c)
If Len(c(r, 1)) > 0 Then
If c(r, 1) <> x Then
If Not d.exists(Trim(CStr(c(r, 1)))) Then
If rng Is Nothing Then
Set rng = col2.Cells(r)
Else
Set rng = Union(rng, col2.Cells(r))
End If
End If
End If
End If
Next
Set CheckColumns = rng
End Function
Edit to include test results:
Number Format:
MS reference to Cells().Errors
Related
So i have the following words in two columns and what I'm trying to do is create an input box where I find the word and extract it as well as the row number. I was able to do it once but now it keeps giving me a debug error which I can't figure out.
Any help would be appreciated(ideally won't have to change much of the code :P)
The any
Quick of
Brown my
Fox lazy
jumps dogs
Over
Option Explicit
Option Base 1
Sub AddMessage()
Dim i As Integer, j As Integer, HT As Variant, nr As Integer, nc As Integer, c As Integer, rng1 As Range, rng2 As Range, row As Integer, rows As Integer
nr = Selection.rows.Count
nc = Selection.Columns.Count
HT = InputBox("Enter column letter:")
Set rng1 = Range("E1:E100")
Set rng2 = Range("F1:F100")
For i = 1 To nr
For j = 1 To nc
If ActiveCell(i, j) = HT Then
Selection.Cells(i, j - 4) = HT
If Cells(i, 1).Value = HT Then
row = Application.WorksheetFunction.match(HT, rng1, 0)
Selection.Cells(i, j - 2) = row
Else
If Cells(i, 2).Value = HT Then
rows = Application.WorksheetFunction.match(HT, rng2, 0)
Selection.Cells(i, j - 2) = row
End If
End If
Next j
Next i
End Sub
you were missing an End If
proper indentation would have helped you figuring it out:
Sub AddMessage()
Dim i As Integer, j As Integer, HT As Variant, nr As Integer, nc As Integer, c As Integer, rng1 As Range, rng2 As Range, row As Integer, rows As Integer
nr = Selection.rows.Count
nc = Selection.Columns.Count
HT = InputBox("Enter column letter:")
Set rng1 = Range("E1:E100")
Set rng2 = Range("F1:F100")
For i = 1 To nr
For j = 1 To nc
If ActiveCell(i, j) = HT Then
Selection.Cells(i, j - 4) = HT
If Cells(i, 1).Value = HT Then
row = Application.WorksheetFunction.Match(HT, rng1, 0)
Selection.Cells(i, j - 2) = row
Else
If Cells(i, 2).Value = HT Then
rows = Application.WorksheetFunction.Match(HT, rng2, 0)
Selection.Cells(i, j - 2) = row
End If '<<<=== missing End If
End If
End If
Next j
Next i
End Sub
Don't know if in your case you'll need a selection, (I recommend not to), here's another piece of code without 'activecells' and 'selections'
Sub tst()
Dim HT As String, Rng As Range
HT = InputBox("Give word to find:")
If Trim(HT) <> "" Then
With Sheets("Sheet1").Range("E1:F100")'assume your data is on Sheet1
Set Rng = .Find(What:=HT, After:=.Cells(.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
If Not Rng Is Nothing Then
Sheets("Sheet1").Cells(Rng.Row, 2) = Rng.Value: Sheets("Sheet1").Cells(Rng.Row, 4) = Rng.Row
Else
MsgBox "No words found"
End If
End With
End If
End Sub
I have a list with 3 variables in the sheet "Combined" in columns A; B; C.
The workbook contains 98 sheets, with those 3 variables still in A; B; C columns but in different combinations and with a fourth column which never repeats itself, as the sheets go on, which i need to bring in the "Combined" sheet, always adding another column for the next sheet I vlookup. : A B C + D(from the next sheet) + E(from the next sheet) and so on.
I have a UDF that Vlookups on 3 based on 3 criterias and a macro that cycles through the sheets and bring the values where i want them. The problem is, it's pretty slow, left it from yesterday and its on sheet 60. Any suggestions on improving it would greatly help, Thank you in advance!
Function ThreeVlookup(Table_Range As Range, Return_Col As Long, Col1_Fnd, Col2_Fnd, Col3_Fnd)
Dim rCheck As Range, bFound As Boolean, lLoop As Long
On Error Resume Next
Set rCheck = Table_Range.Columns(1).Cells(1, 1)
With WorksheetFunction
For lLoop = 1 To .CountIf(Table_Range.Columns(1), Col1_Fnd)
Set rCheck = Table_Range.Columns(1).Find(Col1_Fnd, rCheck, xlValues, xlWhole, xlNext, xlRows, False)
If UCase(rCheck(1, 2)) = UCase(Col2_Fnd) And UCase(rCheck(1, 3)) = UCase(Col3_Fnd) Then
bFound = True
Exit For
End If
Next lLoop
End With
If bFound = True Then
ThreeVlookup = rCheck(1, Return_Col)
Else
ThreeVlookup = ""
End If
End Function
Sub test()
Dim lookupVal1 As Range, lookupVal2 As Range, lookupVal3 As Range, myString As Variant, n&, u As Long
n = Sheets("Combined").[A:A].Cells.Find("*", , , , xlByRows, xlPrevious).Row
u = 4
For j = 2 To Worksheets.Count
For i = 1 To n
Set lookupVal1 = Sheets("Combined").Cells(i, 1)
Set lookupVal2 = Sheets("Combined").Cells(i, 2)
Set lookupVal3 = Sheets("Combined").Cells(i, 3)
myString = ThreeVlookup(Sheets(j).Range("A:D"), 4, lookupVal1, lookupVal2, lookupVal3)
Sheets("Combined").Cells(i, u) = myString
Next i
u = u + 1
Next j
End Sub
Use Arrays to speed it up, my friend! Load all your sheets (or just the current sheet in the loop) into an array in VBA's memory and do the .CountIf and .Find on arrayVar(row) instead of Table_Range.Columns(1).
You will be really surprised how much quicker it goes. Do it!
Here's a tutorial I like on arrays...
http://www.cpearson.com/excel/ArraysAndRanges.aspx
Here's a guy who speed-tested an application like yours...
https://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/
The basics is like this:
Sub Play_With_Arrays()
Dim varArray() As Variant
Dim lngArray() As Long
ReDim varArray(1 To 1000)
ReDim lngArray(1 To 1000)
For A = 1 To 1000
lngArray(A) = A / 2
varArray(A) = A / 2 & " examples"
Next
searchterm = 345
For B = 1 To 1000
If lngArray(B) = searchterm Then
FoundRow = B
End If
Next
searchterm2 = "5 ex"
FoundStrRowCount = 0
For C = 1 To 1000
If InStr(1, varArray(C), searchterm2, vbBinaryCompare) Then
FoundStrRowCount = FoundStrRowCount + 1
End If
Next
MsgBox (FoundRow & " in long array and " & FoundStrRowCount & " in var array")
End Sub
Something like this should be much faster:
Public Function ThreeVLookup(ByVal arg_Col1LookupVal As Variant, _
ByVal arg_Col2LookupVal As Variant, _
ByVal arg_Col3LookupVal As Variant, _
ByVal arg_LookupTable As Range, _
ByVal arg_ReturnColumn As Long) _
As Variant
Dim rConstants As Range, rFormulas As Range
Dim rAdjustedTable As Range
Dim aTable As Variant
Dim i As Long
On Error Resume Next
Set rConstants = arg_LookupTable.SpecialCells(xlCellTypeConstants)
Set rFormulas = arg_LookupTable.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
Select Case (Not rConstants Is Nothing) + 2 * (Not rFormulas Is Nothing)
Case 0: ThreeVLookup = vbNullString
Exit Function
Case -1: Set rAdjustedTable = rConstants
Case -2: Set rAdjustedTable = rFormulas
Case -3: Set rAdjustedTable = Union(rConstants, rFormulas)
End Select
If WorksheetFunction.CountIfs(rAdjustedTable.Resize(, 1), arg_Col1LookupVal, rAdjustedTable.Resize(, 1).Offset(, 1), arg_Col2LookupVal, rAdjustedTable.Resize(, 1).Offset(, 2), arg_Col3LookupVal) = 0 Then
ThreeVLookup = vbNullString
Exit Function
End If
aTable = rAdjustedTable.Value
For i = LBound(aTable, 1) To UBound(aTable, 1)
If aTable(i, 1) = arg_Col1LookupVal And aTable(i, 2) = arg_Col2LookupVal And aTable(i, 3) = arg_Col3LookupVal Then
ThreeVLookup = aTable(i, arg_ReturnColumn)
Exit Function
End If
Next i
End Function
Sub tgr()
Dim wb As Workbook
Dim wsCombined As Worksheet
Dim ws As Worksheet
Dim aResults() As Variant
Dim aCombined As Variant
Dim i As Long, j As Long
Set wb = ActiveWorkbook
Set wsCombined = wb.Sheets("Combined")
aCombined = wsCombined.Range("A1").CurrentRegion.Value
ReDim aResults(1 To UBound(aCombined, 1) - LBound(aCombined, 1) + 1, 1 To wb.Sheets.Count - 1)
For i = LBound(aCombined, 1) To UBound(aCombined, 1)
j = 0
For Each ws In wb.Sheets
If ws.Name <> wsCombined.Name Then
j = j + 1
aResults(i, j) = ThreeVLookup(aCombined(i, 1), aCombined(i, 2), aCombined(i, 3), ws.Range("A:D"), 4)
End If
Next ws
Next i
wsCombined.Range("D1").Resize(UBound(aResults, 1), UBound(aResults, 2)).Value = aResults
End Sub
I have 2 sets of data in 2 sheets having same columns in each sheet.
I want to copy both the sets of data from 2 sheets into a 3rd sheet but in the following format:-
Sheet1
Name Age Gender
Mayur 23 M
Alex 24 M
Maria 25 F
April 19 F
Sheet2
Name Age Gender
Mayur 21 M
Maria 24 F
Alex 24 M
June 20 F
Sheet3
Name1 Name2 Age1 Age2 Gender1 Gender2
Mayur Mayur 23 21 M M
Alex Alex 24 24 M M
Maria Maria 25 24 F F
April 19 F
June 20 F
Now there is one primary column i.e. Name. This column will never be empty.
Both the sheets may not have the data in the same sequence.
Both the sheets may have different entries for the same name.
There could be a name missing in any of the sheets
I have written the whole code which does the following:-
I find out Names from sheet1 in sheet2 & then copy corresponding entries for that name from both the sheets to sheet3.
If a name is not found in sheet2 then it's data is copied as it is as shown above & finally Names in sheet2 are searched in sheet1 if any name is not present in there those entries are copied in sheet3.
Now the searching part runs quite well performance wise but the copying part takes a lot of time.
I have tried other methods of copying the data as well but none runs quite fast.
In actual data there are more than 200 columns & millions of rows.
The whole process runs for more than 6-7 hours.
Could anyone please let me know any alternative faster way of achieving this.
Even if that could reduce the time to an hour or 2 from 7 hours that's still great.
Also I need to highlight the descrepancies which I'm doing that by changing the cell color when there is a mismatch in the data while copying from both the sheets.
Below is the code
Sub findUsingArray()
Dim i As Long
Dim j As Variant
Dim noOfColumnsA As Integer
Dim maxNoOfColumns As Integer
Dim noOfRowsA As Long
Dim noOfRowsB As Long
Dim arrayColumnA() As Variant
Dim arrayColumnB() As Variant
Dim sheet1 As Worksheet
Dim sheet2 As Worksheet
Dim primaryKeyColumn As Integer
Dim result As Long
Set sheet1 = ThisWorkbook.Sheets("Sheet1")
Set sheet2 = ThisWorkbook.Sheets("Sheet2")
noOfColumnsA = sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
maxNoOfColumns = noOfColumnsA * 2
noOfRowsA = sheet1.Cells(Rows.Count, 1).End(xlUp).Row
noOfRowsB = sheet2.Cells(Rows.Count, 1).End(xlUp).Row
'createHeader maxNoOfColumns Used to create header in 3rd sheet
primaryKeyColumn = 1
ReDim arrayColumnA(noOfRowsA)
ReDim arrayColumnB(noOfRowsB)
arrayColumnA = sheet1.Range(sheet1.Cells(1, primaryKeyColumn), sheet1.Cells(noOfRowsA, primaryKeyColumn))
arrayColumnB = sheet2.Range(sheet2.Cells(1, primaryKeyColumn), sheet2.Cells(noOfRowsB, primaryKeyColumn))
result = 2
For i = 2 To noOfRowsA
j = Application.Match(arrayColumnA(i, 1), sheet2.Range(sheet2.Cells(1, primaryKeyColumn), sheet2.Cells(noOfRowsB, primaryKeyColumn)), 0)
If Not IsError(j) Then
result = copyInaRowUsingArray(i, result, j, maxNoOfColumns)
Else
result = copyMissingRow(1, i, result, maxNoOfColumns)
End If
Next i
For i = 2 To noOfRowsB
j = Application.Match(arrayColumnB(i, 1), sheet1.Range(sheet1.Cells(1, primaryKeyColumn), sheet1.Cells(noOfRowsA, primaryKeyColumn)), 0)
If IsError(j) Then
result = copyMissingRow(2, i, result, maxNoOfColumns)
End If
Next i
End Sub
Function copyInaRowUsingArray(sheet1Index As Long, newRowIndex As Long, sheet2index As Variant, noOfColumns As Integer)
Dim i As Long
Dim j As Long
Dim val As Variant
Dim valueA As String
Dim valueB As String
Dim arrayA() As Variant
Dim arrayB() As Variant
Dim sheet1 As Worksheet
Dim sheet2 As Worksheet
Dim sheet3 As Worksheet
Dim rowColoured As Boolean
j = 1
Set sheet1 = ThisWorkbook.Sheets("Sheet1")
Set sheet2 = ThisWorkbook.Sheets("Sheet2")
Set sheet3 = ThisWorkbook.Sheets("Sheet3")
arrayA = Application.Transpose(Application.Transpose(sheet1.Range(sheet1.Cells(sheet1Index, 1), sheet1.Cells(sheet1Index, noOfColumns)).Value))
arrayB = Application.Transpose(Application.Transpose(sheet2.Range(sheet2.Cells(sheet2index, 1), sheet2.Cells(sheet2index, noOfColumns)).Value))
rowColoured = False
With sheet3
For i = 1 To noOfColumns
valueA = arrayA(j)
If Not valueA = "" Then
.Cells(newRowIndex, i).Value = valueA
End If
i = i + 1
valueB = arrayB(j)
If Not valueB = "" Then
.Cells(newRowIndex, i).Value = valueB
End If
If Not StrComp(CStr(valueA), CStr(valueB)) = 0 Then
If Not rowColoured Then
.Range(.Cells(newRowIndex, 1), .Cells(newRowIndex, noOfColumns)).Interior.ColorIndex = 35
rowColoured = True
End If
.Cells(newRowIndex, i).Interior.ColorIndex = 34
.Cells(newRowIndex, i - 1).Interior.ColorIndex = 34
End If
j = j + 1
Next i
copyInaRowUsingArray = newRowIndex + 1
End With
End Function
Function copyMissingRow(sheetNo As Integer, sheetIndex As Long, newRowIndex As Long, noOfColumns As Integer)
Dim i As Long
Dim j As Long
Dim val As Variant
Dim valueA As String
Dim valueB As String
Dim arrayA() As Variant
Dim arrayB() As Variant
Dim sheet1 As Worksheet
Dim sheet2 As Worksheet
Dim sheet3 As Worksheet
j = 1
Set sheet3 = ThisWorkbook.Sheets("Sheet3")
With sheet3
If sheetNo = 1 Then
Set sheet1 = ThisWorkbook.Sheets("Sheet1")
ReDim arrayA(noOfColumns)
arrayA = Application.Transpose(Application.Transpose(sheet1.Range(sheet1.Cells(sheetIndex, 1), sheet1.Cells(sheetIndex, noOfColumns)).Value))
For i = 1 To noOfColumns
valueA = arrayA(j)
If Not valueA = "" Then
.Cells(newRowIndex, i).Value = valueA
End If
i = i + 1
j = j + 1
Next i
.Range(.Cells(newRowIndex, 1), .Cells(newRowIndex, noOfColumns)).Interior.ColorIndex = 46
Else
Set sheet2 = ThisWorkbook.Sheets("Sheet2")
ReDim arrayB(noOfColumns)
arrayB = Application.Transpose(Application.Transpose(sheet2.Range(sheet2.Cells(sheetIndex, 1), sheet2.Cells(sheetIndex, noOfColumns)).Value))
For i = 1 To noOfColumns
i = i + 1
valueB = arrayB(j)
If Not valueB = "" Then
.Cells(newRowIndex, i).Value = valueB
End If
j = j + 1
Next i
.Range(.Cells(newRowIndex, 1), .Cells(newRowIndex, noOfColumns)).Interior.ColorIndex = 3
End If
copyMissingRow = newRowIndex + 1
End With
End Function
As per one of the comments, a dictionary should help do what it is you're after. The dictionary used here saves, from sheet(2), the name as the key and the corresponding row as the value.
Option Explicit
Sub CopyRng(frmSht As Worksheet, frmRow As Integer, offset As Integer, toRow As Integer)
Dim r As Integer
For r = 1 To 3:
Sheets(3).Cells(toRow, offset + 2 * r).Value = frmSht.Cells(frmRow, r).Value
Next
End Sub
Sub InterleaveRows()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
With Sheets(2)
Dim r As Integer, r2 As Integer, r3 As Integer: r3 = 2
Dim val As String
For r = 2 To .Range("A" & .Rows.Count).End(xlUp).row:
dict(.Cells(r, "A").Value) = r
Next
End With
CopyRng Sheets(1), 1, -1, 1
CopyRng Sheets(2), 1, 0, 1
For r = 2 To Sheets(1).Range("A" & Sheets(1).Rows.Count).End(xlUp).row:
val = Sheets(1).Cells(r, "A").Value
If (dict.Exists(val)) Then
r2 = dict(val)
CopyRng Sheets(1), r, -1, r3
CopyRng Sheets(2), r2, 0, r3
dict.Remove val
Else
CopyRng Sheets(1), r, -1, r3
End If
r3 = r3 + 1
Next
For r = 0 To dict.Count - 1
r2 = dict.items()(r)
CopyRng Sheets(2), r2, 0, r3
r3 = r3 + 1
Next
End Sub
The first loop of the 'InterLeaveRows' subroutine populates the dictionary by going through all the entries in Sheet(2). The next two lines writes out the header to sheet(3). The 2nd loop then writes out all values to Sheet(3) that are either in the dictionary (ie in both Sheet(1) and Sheet(2)) or just in Sheet(1); note while doing so entries from the dictionary that are written to Sheet(3) are deleted from the dictionary. The last loop writes out key/val pairs that remain in the dictionary. These are entries that are only in Sheet(2).
I have code here which loops through a list of files; opening them, extracting data and moving it into the main workbook. What i am looking to do get it so the data for abel is in columns c and d but then put varo in f and g etc. the problem that i see is that the placement code is inside the loop so for each i it will just write over the previous line instead of being in a different column all together!
Sub Source_Data()
Dim r
Dim findValues() As String
Dim Wrbk As Workbook
Dim This As Workbook
Dim sht As Worksheet
Dim i
Dim tmp
Dim counter
Dim c As Range
Dim firstAddress
Dim rng As Range
ReDim findValues(1 To 3)
findValues(1) = "abel"
findValues(2) = "varo"
findValues(3) = "Tiger"
counter = 0
r = Range("A1").End(xlDown).Row
Set rng = Range(Cells(1, 1), Cells(r, 1))
Set This = ThisWorkbook
For Each tmp In rng
Workbooks.Open tmp
Set Wrbk = ActiveWorkbook
Set sht = ActiveSheet
For i = 1 To 3
With sht.Range(Cells(1, 1), Range("A1").SpecialCells(xlCellTypeLastCell))
Set c = .Find(findValues(i), LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Offset(0, 2).Value
Do
This.Activate
tmp.Offset(0, 2).Value = tmp.Value
tmp.Offset(0, 3).Value = firstAddress
Set c = .FindNext(c)
counter = counter + 1
Loop While Not c Is Nothing And c.Value = firstAddress
End If
End With
Wrbk.Activate
Next
Wrbk.Close
Next tmp
End Sub
**EDIT:**I know it can be done by adding a multiplier of "i" to the offset value but this makes things bigger than they need to be if i wish to search for 50 keywords
Here is my answer, hope to help you, and as always, if you need an improvement, just tell me.
Sub Source_Data()
Dim r
Dim findValues() As String
Dim Wrbk As Workbook
Dim This As Workbook
Dim sht As Worksheet
Dim i
Dim tmp
Dim counter
Dim c As Range
Dim firstAddress
Dim rng As Range
Dim ColNum 'the columns number var
ReDim findValues(1 To 3)
findValues(1) = "abel"
findValues(2) = "varo"
findValues(3) = "Tiger"
counter = 0
r = Range("A1").End(xlDown).Row
Set rng = Range(Cells(1, 1), Cells(r, 1))
Set This = ThisWorkbook
For Each tmp In rng
Workbooks.Open tmp
Set Wrbk = ActiveWorkbook
Set sht = ActiveSheet
For i = 1 To 3
With sht.Range(Cells(1, 1), Range("A1").SpecialCells(xlCellTypeLastCell))
Set c = .Find(findValues(i), LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Offset(0, 2).Value
Do
This.Activate
Select Case i 'Test var i (the value)
Case "abel" 'in case the value (that is a string) is equal to...
ColNum = 1 'set the var, with the number of the column you want
Case "varo" 'in case the value...
ColNum = 2 'Set the column...
Case "Tiger"
ColNum = 3
Case Else 'In case that the i var not match with anyvalue take this column number
ColNum = 20 'the garbage!
End Select
tmp.Offset(0, ColNum).Value = tmp.Value 'Put the value in the selected columns
tmp.Offset(0, ColNum + 1).Value = firstAddress 'and put the value to the next column of the
'selected column
Set c = .FindNext(c)
counter = counter + 1
Loop While Not c Is Nothing And c.Value = firstAddress
End If
End With
Wrbk.Activate
Next
Wrbk.Close
Next tmp
End Sub
Note:
You need to set the ColNum var to the values that you need, put there the numbers of the columns you really need to store the value of i and the next line is to put the address of the i var
You can just change these two lines:
tmp.Offset(0, 2).Value = tmp.Value
tmp.Offset(0, 3).Value = firstAddress
To this
tmp.Offset(0, 2 + (i-1)*2).Value = tmp.Value
tmp.Offset(0, 3 + (i-1)*2).Value = firstAddress
i have an excel sheet like so:
HEADING <--A1 HEADING <-- this is B1
dhg kfdsl
56 fdjgnm
hgf fdkj
tr
465 gdfkj
gdf53
ry 4353
654 djk
354 <-- a12 blah <-- this is B12
I'm trying to put the range of cells in column A into a variant and remove any data from that variant if the cell in column B (for the same row in column A) is blank. Then i want to copy that variant to a new column (ie col c)
so my expected result is:
HEADING <--C1
dhg
56
hgf
465
ry
654
354 <-- C8
this is the code i have so far:
Dim varData As Variant
Dim p As Long
varData = originsheet.Range("B2:B12")
For p = LBound(varData, 1) To UBound(varData, 1)
If IsEmpty(varData(p, 1)) Then
remove somehow
End If
Next p
Dim bRange As range
Set bRange = originsheet.range("B2:B12")
Dim aCell, bCell, cCell As range
Set cCell = originsheet.Cells(2, 3) 'C2
For Each bCell In bRange
If bCell.Text <> "" Then
Set aCell = originsheet.Cells(bCell.Row, 1)
cCell.Value2 = aCell.Value2
Set cCell = originsheet.Cells(cCell.Row + 1, 3)
End If
Next bCell
Personally, I think your making this simple job harder, but here's how to do it the way you wanted:
Public Sub Test()
Dim Arange As Variant, Brange As Variant, Crange() As Variant
Dim i As Integer, j As Integer
Arange = Range("A2:A12")
Acount = Application.WorksheetFunction.CountA(Range("B2:B12"))
Brange = Range("B2:B12")
j = 1
ReDim Crange(1 To Acount, 1 To 1)
For i = 1 To UBound(Arange)
If Brange(i, 1) <> "" Then
Crange(j, 1) = Arange(i, 1)
j = j + 1
End If
Next i
Range("C2:C" & j) = Crange
End Sub
Try:
With ActiveSheet.UsedRange
.Cells(2, "C").Resize(.Rows.Count).Value = Cells(2, "A").Resize(.Rows.Count).Value
.Cells(2, "B").Resize(.Rows.Count).SpecialCells(xlCellTypeBlanks).Offset(, 1).Delete shift:=xlUp
End With
EDIT:
This is better:
With Range("A2", Cells(Rows.Count, "A").End(xlUp))
Cells(2, "C").Resize(.Rows.Count).Value = .Value
.Offset(, 1).SpecialCells(xlCellTypeBlanks).Offset(, 1).Delete shift:=xlUp
End With
You could also do it with advanced filter and no VBA.
Sub Main()
Dim rValues As Range
Dim vaIn As Variant
Dim vaTest As Variant
Dim aOut() As Variant
Dim i As Long
Dim lCnt As Long
Set rValues = Sheet1.Range("A2:A12")
vaIn = rValues.Value
vaTest = rValues.Offset(, 1).Value
ReDim aOut(1 To Application.WorksheetFunction.CountA(rValues.Offset(, 1)), 1 To 1)
For i = LBound(vaIn, 1) To UBound(vaIn, 1)
If Len(vaTest(i, 1)) <> 0 Then
lCnt = lCnt + 1
aOut(lCnt, 1) = vaIn(i, 1)
End If
Next i
Sheet1.Range("C2").Resize(UBound(aOut, 1)).Value = aOut
End Sub