I have an Excel Sheet where some rows may contain the same data as other rows. I need a macro to sum all the values in that column and delete all the duplicates rows, except for the first one, which contains the sum of the rest.
I have tried multiple versions of code and the code that produces the results closest to what I need looks like this, but this code contains one problem is: infinite loop.
Sub delet()
Dim b As Integer
Dim y As Worksheet
Dim j As Double
Dim k As Double
Set y = ThisWorkbook.Worksheets("Sheet1")
b = y.Cells(Rows.Count, 2).End(xlUp).Row
For j = 1 To b
For k = j + 1 To b
If Cells(j, 2).Value = Cells(k, 2).Value Then
Cells(j, 3).Value = (Cells(j, 3).Value + Cells(k, 3).Value)
Rows(k).EntireRow.Delete
k = k - 1
ElseIf Cells(j, 2).Value <> Cells(k, 2).Value Then
k = k
End If
Next
Next
End Sub
I would recommend getting the data in an array and then do the relevant operation. This is a small range and it may not affect the performance but for a larger dataset it will matter.
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long, j As Long
Dim MyAr As Variant, outputAr As Variant
Dim col As New Collection
Dim itm As Variant
Dim totQty As Double
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Find last row of col A
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Get those value in an array
MyAr = .Range("A2:C" & lRow).Value2
'~~> Get unique collection of Fam.
For i = LBound(MyAr) To UBound(MyAr)
If Len(Trim(MyAr(i, 2))) <> 0 Then
On Error Resume Next
col.Add MyAr(i, 2), CStr(MyAr(i, 2))
On Error GoTo 0
End If
Next i
'~~> Prepare array for output
ReDim outputAr(1 To col.Count, 1 To 3)
i = 1
For Each itm In col
'~~> Get Product
For j = LBound(MyAr) To UBound(MyAr)
If MyAr(i, 2) = itm Then
outputAr(i, 1) = MyAr(i, 1)
Exit For
End If
Next j
'~~> Fam.
outputAr(i, 2) = itm
totQty = 0
'~~> Qty
For j = LBound(MyAr) To UBound(MyAr)
If MyAr(j, 2) = itm Then
totQty = totQty + Val(MyAr(j, 3))
End If
Next j
outputAr(i, 3) = totQty
i = i + 1
Next itm
'~~> Copy headers
.Range("A1:C1").Copy .Range("G1")
'~~> Write array to relevant range
.Range("G2").Resize(UBound(outputAr), 3).Value = outputAr
End With
End Sub
Output
If VBA isn't essential and you've got 365:
In cell G2 enter the formula =UNIQUE(A2:B11)
In cell I2 enter the formula =SUMIFS(C2:C11,A2:A11,INDEX(G2#,,1),B2:B11,INDEX(G2#,,2))
Remove Duplicates with Sum
Adjust the values in the constants section.
Note that if you choose the same worksheets and "A1", you will overwrite.
The Code
Option Explicit
Sub removeDupesSum()
Const sName As String = "Sheet1"
Const dName As String = "Sheet1"
Const dFirst As String = "G1"
Dim wb As Workbook: Set wb = ThisWorkbook
' Write values from Source Range to Data Array.
Dim Data As Variant
Data = wb.Worksheets(sName).Cells(1).CurrentRegion.Value
' Write unique values from Data Array to Unique Sum Dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim arr As Variant: ReDim arr(2 To UBound(Data, 1)) ' for first column
Dim n As Long: n = 1
Dim i As Long
For i = 2 To UBound(Data, 1)
If dict.Exists(Data(i, 2)) Then
dict(Data(i, 2)) = dict(Data(i, 2)) + Data(i, 3)
Else
n = n + 1
arr(n) = Data(i, 1)
dict(Data(i, 2)) = Data(i, 3)
End If
Next i
Dim Result As Variant: ReDim Result(1 To dict.Count + 1, 1 To 3)
' Write headers.
For i = 1 To 3
Result(1, i) = Data(1, i)
Next i
Erase Data
' Write 'body'.
Dim Key As Variant
i = 1
For Each Key In dict.Keys
i = i + 1
Result(i, 1) = arr(i)
Result(i, 2) = Key
Result(i, 3) = dict(Key)
Next Key
' Write values from Result Array to Destination Range.
With wb.Worksheets(dName).Range(dFirst).Resize(, 3)
.Resize(i).Value = Result
.Resize(.Worksheet.Rows.Count - .Row - i + 1).Offset(i).ClearContents
End With
End Sub
Related
please help i want to sort the name column such that each name starts after every blank cell.
I want it look something like this..pls help it's a pretty long column
Option Explicit
Sub SetNamePosition()
Dim arr As Variant
Dim i As Long: i = 1 ' for Loop
Dim j As Long: j = 1 ' for Array
Dim lastRow As Long: lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim rngColB As Range: Set rngColB = Range("B2:B" & lastRow)
Dim rngNames As Range: Set rngNames = Range("C1") ' Temporary range
' Get column B names only
rngColB.SpecialCells(xlCellTypeConstants, 2).Copy
rngNames.PasteSpecial (xlPasteValues)
Application.CutCopyMode = False
Set rngNames = Range(rngNames, rngNames.End(xlDown))
' Load rngNames to array
arr = Application.Transpose(rngNames)
' Clear rng of column B and rngNames
rngColB.Clear
rngNames.Clear
' Insert names
For i = 2 To lastRow
' set name
Cells(i, 1).Offset(0, 1).Value = arr(j)
' find next cell
i = Cells(i, 1).End(xlDown).Row + 1
j = j + 1
Next i
End Sub
I's probably better to remove the empty ranges before making the array, but here's one way to distribute the names:
Loading the range ito an array, then go through the numbers and look for empty ranges.
This assumes that we are working with column "A" and "B" (1 and 2), starting at the top.
Sub test()
Dim arr As Variant
Dim lastRow As Long, i As Long, j As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
arr = Application.Transpose(Range("B2:B" & lastRow))
Range("B2:B" & lastRow).Clear
j = 1
For i = 2 To lastRow
Cells(i, 2) = arr(j)
j = j + 1
If j >= UBound(arr) Then Exit For
While arr(j) = "" And j < UBound(arr)
j = j + 1
Wend
While Not Cells(i, 1).Value = ""
i = i + 1
Wend
Next i
End Sub
Any leftover names will be removed
I currently have two spreadsheets: one that pulls data from a SQL Server and is a data dump and one that needs to have those values populated into them. For the sake of simplicity, I've compiled a mini prototype to use for the purpose of my question. Things to note, the data dump sheet will have a varying amount of rows, however the columns will be static which should hopefully make for easy mapping. What I need my macro to be able to accomplish is to
Check if an ID value matches the one directly below it, if so
Check if the Spouse_Indicator field has an "N" or "Y" value
If the indicator is an "N" value then I need the corresponding rows from the employer and title fields to be populated into the student table
If the indicator is a "Y" value then I need the corresponding rows from the employer and title fields to be populated into the spouse table
If there is a sequence where the ID does not match the one directly below it, the data automatically gets populated into the student table
The problem that I am having with the way that my macro is set up is that only the most recent ID with a "N" indicator is getting populated into every cell of the student table whereas I need only unique values to be populated until the last ID has been read. The image attached shows a small sample size of the data, the first table shows what my macro is producing while the last table shows my target. I am also including my code to show what I've gotten so far. Let me know if I need to clarify anything, thanks a bunch.
Sub test2()
Dim wb As Workbook
Dim ws As Worksheet
Dim id As Range
Dim cell As Range
Dim student_employer As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set id = ws.Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row)
Set student_employer = ws.Range("G3:G8")
For Each cell In id
If cell.Value = cell.Offset(1, 0).Value And cell.Offset(0, 1).Value = "N" Then
cell.Offset(0, 2).Copy student_employer.Cells
End If
Next
MsgBox ("DONE")
End Sub
I've edited my code and it is somewhat capturing what I am trying to accomplish, however I need the values to be pasted into the next empty cell, while mine currently skips the amount of cells depending on when the next copy-paste takes place.
Sub test2()
Dim id As Long
Dim x As Long
Dim emp As Range
Set emp = Range("G3:G8")
id = Cells(Rows.Count, "A").End(xlUp).Row
For x = 2 To id
If Cells(x, 1).Value = Cells(x, 1).Offset(1, 0) Then
Cells(x, 1).Offset(0, 2).Copy Cells(x, 6).Offset(1, 0)
End If
Next x
MsgBox ("DONE")
End Sub
Copy Unique Rows
Adjust the values in the constants section. If you feel like it, use the out-commented constants and sCols to get rid of the 'magic' numbers (1, 2, 3, 4).
For the sake of simplicity, it is assumed that the source data starts in cell A1 (CurrentRegion).
Option Explicit
Sub test1()
Const sName As String = "Sheet1"
'Const sCritCol As Long = 2
'Const sColsList As String = "1,3,4"
'Const scCount As Long = 4
Const sCrit1 As String = "N"
Const sCrit2 As String = "Y"
Const dName As String = "Sheet1"
Const dFirst As String = "F1"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion
If srg.Columns.Count <> 4 Then Exit Sub
Dim srCount As Long: srCount = srg.Rows.Count
If srCount = 1 Then Exit Sub
Dim sData As Variant: sData = srg.Value
'Dim sCols() As String: sCols = Split(sColsList, ",")
Dim dict1 As Object: Set dict1 = CreateObject("Scripting.Dictionary")
dict1.CompareMode = vbTextCompare
Dim dict2 As Object: Set dict2 = CreateObject("Scripting.Dictionary")
dict2.CompareMode = vbTextCompare
Dim cDat As Variant: ReDim cDat(1 To 3)
Dim Key As Variant
Dim sCrit As Variant
Dim r As Long
For r = 2 To srCount
sCrit = sData(r, 2)
Select Case UCase(CStr(sCrit))
Case sCrit1
Key = sData(r, 1)
If Not dict1.Exists(Key) Then
cDat(1) = sData(r, 1)
cDat(2) = sData(r, 3)
cDat(3) = sData(r, 4)
dict1(Key) = cDat
End If
Case sCrit2
Key = sData(r, 1)
If Not dict2.Exists(Key) Then
cDat(1) = sData(r, 1)
cDat(2) = sData(r, 3)
cDat(3) = sData(r, 4)
dict2(Key) = cDat
End If
End Select
Next r
Dim drCount As Long: drCount = dict1.Count + dict2.Count + 4
Dim dData As Variant: ReDim dData(1 To drCount, 1 To 3)
r = 1
dData(r, 1) = "student"
r = r + 1
dData(r, 1) = sData(1, 1)
dData(r, 2) = sData(1, 3)
dData(r, 3) = sData(1, 4)
Dim n As Long
If dict1.Count > 0 Then
For Each Key In dict1.Keys
r = r + 1
For n = 1 To 3
dData(r, n) = dict1(Key)(n)
Next n
Next Key
End If
r = r + 1
dData(r, 1) = "spouse"
r = r + 1
dData(r, 1) = sData(1, 1)
dData(r, 2) = sData(1, 3)
dData(r, 3) = sData(1, 4)
If dict2.Count > 0 Then
For Each Key In dict2.Keys
r = r + 1
For n = 1 To 3
dData(r, n) = dict2(Key)(n)
Next n
Next Key
End If
Application.ScreenUpdating = False
' Write.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim drg As Range: Set drg = dws.Range(dFirst).Resize(r, 3)
drg.Clear ' because of merged cells
drg.Value = dData
' Clear below.
Dim crg As Range
Set crg = drg.Resize(dws.Rows.Count - drg.Row - r + 1).Offset(r)
crg.Clear
' Format 'student'
With drg.Rows(1)
.Cells(1).Font.Bold = True
.MergeCells = True
.HorizontalAlignment = xlCenter
.BorderAround xlContinuous, xlThick
End With
' Format 'spouse'.
With drg.Rows(dict1.Count + 3)
.Cells(1).Font.Bold = True
.MergeCells = True
.HorizontalAlignment = xlCenter
.BorderAround xlContinuous, xlThick
End With
' Format all.
drg.EntireColumn.AutoFit
Application.ScreenUpdating = True
MsgBox ("DONE")
End Sub
I have autofiltered a worksheet and am trying to establish the unique values within the filtered data. I feel like I have the correct approach, but the my results only show 2 of the possible 8 unique values.
Private Sub GetAllCampusDomains(DomainCol As Collection)
Dim data(), dict As Object, r As Long, i%, lastrow As Long
Set dict = CreateObject("Scripting.Dictionary")
'Clear the previous filter
shtData.ShowAllData
'Filter the data
shtData.Range("A:Y").AutoFilter Field:=6, Criteria1:=shtSetup.Range("CampusName") 'SchoolName
shtData.Range("A:Y").AutoFilter Field:=9, Criteria1:="DomainPerformance" 'ColI
'Inspect the visible cells in ColP
lastrow = shtData.Cells(shtData.Rows.Count, "P").End(xlUp).row
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
data = WorksheetFunction.Transpose(dict.keys())
'Walk through the unique values
For i = 1 To UBound(data)
Debug.Print data(i, 1)
'DomainCol.Add data(i, 1)
Next i
End Sub
The error seems to have to do with this line:
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
This call only seems to create a 90x1 sized array, when it should be much bigger.
I greatly appreciate your help!
Josh
Non-Contiguous Column Range to Jagged Array
Instead of...
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
...use the following...
Private Sub GetAllCampusDomains(DomainCol As Collection)
'...
Dim rng As Range
Set rng = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
getNonContiguousColumn Data, rng
'Find the unique values
Dim j As Long
For j = 0 To UBound(Data)
For r = 1 To UBound(Data(j))
dict(Data(j)(r, 1)) = Empty
Next r
Next j
'...
End Sub
...backed up by the following:
Sub getNonContiguousColumn(ByRef Data As Variant, _
NonContiguousColumnRange As Range, _
Optional FirstIndex As Long = 0)
Dim j As Long
j = FirstIndex - 1
ReDim Data(FirstIndex To NonContiguousColumnRange.Areas.Count + j)
Dim ar As Range
Dim OneCell As Variant
ReDim OneCell(1 To 1, 1 To 1)
For Each ar In NonContiguousColumnRange.Areas
j = j + 1
If ar.Cells.Count > 1 Then
Data(j) = ar.Value
Else
OneCell(1, 1) = ar.Value
Data(j) = OneCell
End If
Next ar
End Sub
Test the previous Sub with something like the following:
Sub testGetNCC()
Const rngAddr As String = "A2:A20"
Dim Data As Variant
Dim rng As Range
Set rng = Range(rngAddr).SpecialCells(xlCellTypeVisible)
getNonContiguousColumn Data, rng
Dim j As Long, i As Long
For j = 0 To UBound(Data)
For i = 1 To UBound(Data(j))
Debug.Print Data(j)(i, 1)
Next i
Next j
End Sub
Please, replace this piece of code:
data = shtData.Range("P2:P" & lastrow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
with the next one:
Dim rng As Range, C As Range
Set rng = shtData.Range("P2:P" & lastRow).SpecialCells(xlCellTypeVisible)
'Find the unique values
For Each C In rng.cells
dict(C.Value) = Empty
Next
Your initial code iterates between the first area range cells.
The second one will iterate between all visible range cells...
I have a list of lists in Excel. There is some specifications (name, age, country, etc) in the first column and values in the second column. I don't want to repeat the same specifications over and over again. What I want to show in the picture. I tried =VLOOKUP() but it did not work perfectly because the lists do not include the same specifications. How can I achieve this?
A VBA macro can generate the results, and also the list of parameters for the first column of results.
To enter this Macro (Sub), alt-F11 opens the Visual Basic Editor.
Ensure your project is highlighted in the Project Explorer window.
Then, from the top menu, select Insert/Module and
paste the code below into the window that opens.
Be sure to set the Reference as stated in the Note in the macro
To use this Macro (Sub), alt-F8 opens the macro dialog box. Select the macro by name, and RUN.
This macro generates the list with the parameter list in the first column. It could be easily rewritten to have the parameter list in the first row, if that is preferable.
Option Explicit
'Set Reference to Microsoft Scripting Runtime
Sub GroupLists()
Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
Dim vSrc As Variant, vRes As Variant
Dim dictParams As Dictionary
Dim sParam As String
Dim I As Long, J As Long, K As Long
Dim V As Variant
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet1")
Set rRes = wsRes.Cells(1, 5)
With wsSrc
vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=2)
End With
'Get unique list of Parameters with row number
'Also count the number of entries for number of columns in final result
J = 0
Set dictParams = New Dictionary
K = 0 'row number for parameter
For I = 1 To UBound(vSrc, 1)
J = J + 1 'column count
Do
If Not dictParams.Exists(vSrc(I, 1)) Then
K = K + 1
dictParams.Add Key:=vSrc(I, 1), Item:=K
End If
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = ""
If I > UBound(vSrc) Then Exit For
Next I
'Create results array
ReDim vRes(1 To dictParams.Count, 1 To J + 1)
'Populate Column 1
For Each V In dictParams.Keys
vRes(dictParams(V), 1) = V
Next V
'Populate the data
J = 1 'column number
For I = 1 To UBound(vSrc, 1)
J = J + 1
Do
sParam = vSrc(I, 1)
vRes(dictParams(sParam), J) = vSrc(I, 2)
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = ""
If I > UBound(vSrc) Then Exit For
Next I
'Write the results
Set rRes = rRes.Resize(UBound(vRes, 1), UBound(vRes, 2))
rRes.EntireColumn.Clear
rRes = vRes
End Sub
EDIT: Macro modified to reflect the "real data"
Please note: You will need to add a second worksheet for the results. I named it "Sheet2"
Option Explicit
'Set Reference to Microsoft Scripting Runtime
Sub GroupLists()
Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
Dim vSrc As Variant, vRes As Variant
Dim dictParams As Dictionary
Dim sParam As String
Dim I As Long, J As Long, K As Long
Dim V As Variant
Dim sDelim As String 'Differentiates each record
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet2")
Set rRes = wsRes.Cells(1, 1)
With wsSrc
vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=2)
sDelim = vSrc(1, 1)
End With
'Get unique list of Parameters with row number
'Also count the number of entries for number of columns in final result
J = 0
Set dictParams = New Dictionary
K = 0 'row number for parameter
For I = 1 To UBound(vSrc, 1)
J = J + 1 'column count
Do
If Not dictParams.Exists(vSrc(I, 1)) Then
K = K + 1
dictParams.Add Key:=vSrc(I, 1), Item:=K
End If
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = sDelim
If I > UBound(vSrc) Then
Exit For
Else
I = I - 1
End If
Next I
'Create results array
ReDim vRes(1 To dictParams.Count, 1 To J + 1)
'Populate Column 1
For Each V In dictParams.Keys
vRes(dictParams(V), 1) = V
Next V
'Populate the data
J = 1 'column number
For I = 1 To UBound(vSrc, 1)
J = J + 1
Do
sParam = vSrc(I, 1)
vRes(dictParams(sParam), J) = vSrc(I, 2)
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = sDelim
If I > UBound(vSrc) Then
Exit For
Else
I = I - 1
End If
Next I
'Write the results
Set rRes = rRes.Resize(UBound(vRes, 1), UBound(vRes, 2))
rRes.EntireColumn.Clear
rRes = vRes
End Sub
EDIT2: This macro is a modification of the above, which lists the results in the opposite orientation. It may be more useful.
Option Explicit
'Set Reference to Microsoft Scripting Runtime
Sub GroupListsVertical()
Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
Dim vSrc As Variant, vRes As Variant
Dim dictParams As Dictionary
Dim sParam As String
Dim I As Long, J As Long, K As Long
Dim V As Variant
Dim sDelim As String 'Differentiates each record
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet3")
Set rRes = wsRes.Cells(1, 1)
With wsSrc
vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=2)
sDelim = vSrc(1, 1)
End With
'Get unique list of Parameters with row number
'Also count the number of entries for number of columns in final result
J = 0
Set dictParams = New Dictionary
K = 0 'column number for parameter
For I = 1 To UBound(vSrc, 1)
J = J + 1 'row count
Do
If Not dictParams.Exists(vSrc(I, 1)) Then
K = K + 1
dictParams.Add Key:=vSrc(I, 1), Item:=K
End If
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = sDelim
If I > UBound(vSrc) Then
Exit For
Else
I = I - 1
End If
Next I
'Create results array
ReDim vRes(1 To J + 1, 1 To dictParams.Count)
'Populate row 1
For Each V In dictParams.Keys
vRes(1, dictParams(V)) = V
Next V
'Populate the data
J = 1 'row number
For I = 1 To UBound(vSrc, 1)
J = J + 1
Do
sParam = vSrc(I, 1)
vRes(J, dictParams(sParam)) = vSrc(I, 2)
I = I + 1
If I > UBound(vSrc) Then Exit Do
Loop Until vSrc(I, 1) = sDelim
If I > UBound(vSrc) Then
Exit For
Else
I = I - 1
End If
Next I
'Write the results
Set rRes = rRes.Resize(UBound(vRes, 1), UBound(vRes, 2))
rRes.EntireColumn.Clear
rRes = vRes
rRes.EntireColumn.AutoFit
End Sub
Use following ARRAY formulas.
Cell F2 formula
=IFERROR(INDEX($B$1:$B$20,SMALL(IF($A$1:$A$20=$E2,ROW($B$1:$B$20),""),COLUMN(A:A))),"")
Cell E19 formula
=IFERROR(INDEX($B$1:$B$20,SMALL(IF($A$1:$A$20=$E2,ROW($B$1:$B$20),""),COLUMN(A:A))),"")
Press CTRL+SHIFT+ENTER to evaluate the formula as it is an array formula.
I have to loop search multiple ranges and find match to 100k + records. Problem is I get mismatch error when assigning value to variant Arr2(i, 1).
Dim Arr1, Arr2 As Variant
Dim Wks0, Wks1 As Worksheet
Dim i As Integer
Dim Row0, Row1 As Long
Dim C As Object
Set Wks0 = Sheets("HOST")
Set Wks1 = Sheets("OFICI_BANC_USA")
'-- Create array of range -------------------------------------------*
Row0 = Wks0.Cells(Rows.Count, "A").End(xlUp).Row
Row1 = Wks1.Cells(Rows.Count, "A").End(xlUp).Row
Arr1 = Wks1.Range("A2:A" & Row1)
'-- Loop create value on sheet OFIC_BANC_USA found value in sheet HOST -----*
For i = 1 To 5 'UBound(Arr1)
With Wks0.Range("A2:A" & Row0)
Set C = .Find(Arr1(i, 1), LookAt:=xlPart,SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not C Is Nothing Then
'ReDim Preserve Arr2(i, 1)
Arr2(i, 1) = "OK"
Else
Arr2(i, 1) = "NO"
End If
End With
Next
' Transpose new array onto worksheet -------------------------------*
Wks1.Range("B2:B6") = WorksheetFunction.Transpose(Arr2)
'Arr1 = Nothing
'Arr2 = Nothing
I think you want to deal with a two-dimensioned array for the values coming in from wks1 (since you have no choice in the matter) and a single dimensioned array to hold the OK / NO values before stuffing them back into the worksheet.
Sub t()
Dim Arr0() As Variant, Arr1() As Variant, Arr2() As Variant
Dim Wks0 As Worksheet, Wks1 As Worksheet
Dim i As Long
Dim Row0 As Long, Row1 As Long
Dim C As Range
Set Wks0 = Sheets("HOST")
Set Wks1 = Sheets("OFICI_BANC_USA")
'-- Create array of range -------------------------------------------*
Row0 = Wks0.Cells(Wks0.Rows.Count, "A").End(xlUp).Row
Row1 = Wks1.Cells(Wks1.Rows.Count, "A").End(xlUp).Row
Arr1 = Wks1.Range("A2:A" & Row1)
'-- Loop create value on sheet OFIC_BANC_USA found value in sheet HOST -----*
For i = 1 To UBound(Arr1, 1)
With Wks0.Range("A2:A" & Row0)
Set C = .Find(Arr1(i, 1), LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
ReDim Preserve Arr2(i) '<~~ NOTE ReDim single dimensioned array here!
If Not C Is Nothing Then
Arr2(i) = "OK"
Else
Arr2(i) = "NO"
End If
End With
Next
' Transpose new array onto worksheet -------------------------------*
Wks1.Range("B2").Resize(UBound(Arr2), 1) = WorksheetFunction.Transpose(Arr2)
End Sub
Note where I've redimmed arr2. It's going to get a value either way so you need to extend its size in preparation to receive an OK / NO.
Scripting.Dictionary
Sub tt()
Dim arr As Variant, dHOST As Object
Dim Wks0 As Worksheet, Wks1 As Worksheet
Dim i As Long, j As Long
Dim Row0 As Long, Row1 As Long
Dim c As Range, rHOST As Range
Debug.Print Timer
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set Wks0 = Worksheets("HOST")
Set Wks1 = Sheets("OFICI_BANC_USA")
Set dHOST = CreateObject("Scripting.Dictionary")
dHOST.CompareMode = vbTextCompare
'-- Create dictionary of HOST range --------------------------
Row0 = Wks0.Cells(Wks0.Rows.Count, "A").End(xlUp).Row
arr = Wks0.Range("A2:D" & Row0).Value2
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
'If Not dHOST.Exists(arr(i, j)) Then _
dHOST.Item(arr(i, j)) = j '<~~ for first match (adds 1½ seconds)
dHOST.Item(arr(i, j)) = j '<~~ for overwrite match
Next j
Next i
'-- Create array of OFICI_BANC_USA range ----------------------
Row1 = Wks1.Cells(Wks1.Rows.Count, "A").End(xlUp).Row
arr = Wks1.Range("A2:E" & Row1).Value2
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) + 1 To UBound(arr, 2)
arr(i, j) = "NO" '<~~ seed all NO matches
Next j
Next i
'-- Loop arrayed values from sheet OFIC_BANC_USA found value in dictionary HOST values --
For i = LBound(arr, 1) To UBound(arr, 1)
If dHOST.Exists(arr(i, 1)) Then _
arr(i, dHOST.Item(arr(i, 1)) + 1) = "OK"
Next i
' Stuff it all back into worksheet -------------------------------*
With Wks1.Range("A2:E" & Row1)
.Cells = arr
End With
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
Debug.Print Timer
End Sub
200K records in column A of OFICI_BANC_USA worksheet
4 columns # 50K rows each in HOSTS worksheet
~76% match rate
14.73 seconds start-to-finish
In addition to #VincentG's comment, you need to explicitly state which Rows you're using. Also, I uncommented the ReDim, and it seems to be working now:
Sub t()
Dim Arr0() As Variant, Arr1() As Variant, Arr2() As Variant
Dim Wks0 As Worksheet, Wks1 As Worksheet
Dim i As Integer
Dim Row0 As Long, Row1 As Long
Dim C As Object
Set Wks0 = Sheets("HOST")
Set Wks1 = Sheets("OFICI_BANC_USA")
'-- Create array of range -------------------------------------------*
Row0 = Wks0.Cells(Wks0.Rows.Count, "A").End(xlUp).Row
'Arr0 = Wks0.Range("A2:A" & Row0)
Row1 = Wks1.Cells(Wks1.Rows.Count, "A").End(xlUp).Row
Arr1 = Wks1.Range("A2:A" & Row1)
'-- Loop create value on sheet OFIC_BANC_USA found value in sheet HOST -----*
For i = 1 To 5 'UBound(Arr1)
With Wks0.Range("A2:A" & Row0)
Set C = .Find(Arr1(i, 1), LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not C Is Nothing Then
ReDim Preserve Arr2(i, 1)
Arr2(i, 1) = "OK"
Else
Arr2(i, 1) = "NO"
End If
End With
Next
' Transpose new array onto worksheet -------------------------------*
Wks1.Range("B2:B6") = WorksheetFunction.Transpose(Arr2)
'Arr0 = Nothing
'Arr1 = Nothing
'Arr2 = Nothing
End Sub
I think I am understanding what you are trying to do. I set my two sheets up like this:
Then using the following code:
Sub jorge()
Application.ScreenUpdating = False
Dim Arr1 As Variant, Arr2 As Variant, Arr3 As Variant
Dim Wks0 As Worksheet, Wks1 As Worksheet
Dim i As Long, j As Long, k As Long
Dim Row0 As Long, Row1 As Long
Set Wks0 = Sheets("HOST")
Set Wks1 = Sheets("OFICI_BANC_USA")
'-- Create array of range -------------------------------------------*
Row0 = Wks0.Cells(Rows.Count, "A").End(xlUp).Row
Row1 = Wks1.Cells(Rows.Count, "A").End(xlUp).Row
Arr1 = Wks1.Range("A2:A" & Row1)
ReDim Arr2(1 To Row1, 1 To 4)
Arr3 = Wks0.Range("A2:D" & Row0)
'-- Loop create value on sheet OFIC_BANC_USA found value in sheet HOST -----*
For i = 1 To UBound(Arr1, 1)
For j = 1 To UBound(Arr3, 2)
Arr2(i, j) = "NO"
For k = 1 To UBound(Arr3, 1)
If Arr3(k, j) = Arr1(i, 1) Then
Arr2(i, j) = "OK"
Exit For
End If
Next k
Next j
Next i
Wks1.Range("B2").Resize(Row1, 4).value = Arr2
Application.ScreenUpdating = true
End Sub
I get this:
This formula will do the same thing, put this in B2:
=IF(ISNUMBER(MATCH($A2,HOST!A:A,0)),"OK","NO")
Copy across and down. This may be prohibitive with the sheer number of calculations, but it is here if you want to try it.