Load table into array and combine all duplicates- Excel VBA - arrays

I have many tables that need data combined. I have combined some of the tables into a test table to test the code. I am sorting the unique values in column 'B' a-z before running my code. It is very slow with only ~3500 records. The actual total is over 100,000 records. I'm curious to see if I can load the whole table to an array and perform the same functions, but I'm not sure if it is possible.
My table structure is:
Unique ID
First
Last
Company
etc.
A1
John
A1
Doe
A1
company1
A2
Jay
Varnado
A3
Joe
Snuffy
A3
M.
company2
The desired outcome is:
Unique ID
First
Last
Company
etc.
A1
John
Doe
company1
A1
John
Doe
company1
A1
John
Doe
company1
A2
Jay
Varnado
A3
Joe M.
Snuffy
company2
A3
Joe M.
Snuffy
company2
Dim cel As Range, rng As Range, r As Range
Dim arr(14) As String, temp As String
Dim i As Long, b As Long, j As Long, lRow As Long, lRec As Long, c As Long
Dim ii As Integer, v As Integer, col As Integer
Dim dict As Scripting.Dictionary
Dim str() As String
Dim BenchMark As Double
BenchMark = Timer
lRow = Sheet3.Cells(Rows.Count, 1).End(xlUp).Row
For c = 3 To lRow
Debug.Print c
Set cel = Sheet3.Range("B" & c)
If Trim(cel.Offset(1, 0)) = Trim(cel.Value) Then
'Determine range of like keys
i = 1
Do Until cel.Offset(i, 0).Value <> cel.Value
i = i + 1
Loop
lRec = cel.Offset(i, 0).Row - 1
'Compare data
For i = 3 To 16
ii = i - 3
'Create rng and loop through each column
Set rng = Sheet3.Range(Sheet3.Cells(c, i), Sheet3.Cells(lRec, i))
Set dict = New Scripting.Dictionary 'CreateObject("Scripting.Dictionary")
For Each r In rng
If dict.Exists(r.Value) = False And Len(r.Value) > 0 Then
dict.Add r.Value, r.Value
End If
Next r
'Add to string array
'Debug.Print Split(Join(dict.Keys, "|"), "|")
str = Split(Join(dict.Keys, ","), ",")
arr(ii) = Join(str, ",")
Set dict = Nothing
Next i
'Set range equal to array
For j = cel.Row To lRec
v = 0
For col = 3 To 16
Sheet3.Cells(j, col) = arr(v)
Sheet3.Cells(j, col) = arr(v)
v = v + 1
Next col
Next j
'Go to last cell in range
c = lRec
Else: GoTo NextCel
End If
'Clear array
NextCel:
On Error Resume Next
'Debug.Print Join(arr, ",")
Erase arr
On Error GoTo 0
Next c
MsgBox ("Done in " & Timer - BenchMark)
End Sub

Assuming ID is in column B and output as single lines per ID to Sheet1 or with duplicates to Sheet2.
Option Explicit
Sub Process()
Dim dict As Object, key
Dim iLastRow As Long, n As Long, r As Long
Dim c As Integer, s As String
Dim arIn, arOut, t0 As Single: t0 = Timer
Set dict = CreateObject("Scripting.Dictionary")
iLastRow = Sheet3.Cells(Rows.Count, "B").End(xlUp).Row
arIn = Sheet3.Range("A1").Resize(iLastRow, 16).Value2
n = 0
' determine number of unique ids
For r = 3 To iLastRow
key = Trim(arIn(r, 2))
If Len(key) > 0 Then
If Not dict.exists(key) Then
n = n + 1
dict.Add key, n
End If
End If
Next
' dimension output array and fill
ReDim arOut(1 To n, 1 To 15)
For r = 3 To iLastRow
key = Trim(arIn(r, 2))
n = dict(key)
arOut(n, 1) = key
' concat columns
For c = 3 To 16
s = Trim(arIn(r, c))
If Len(s) > 0 Then
arOut(n, c - 1) = arOut(n, c - 1) & " " & s
End If
Next
Next
' output to sheet1
Sheet1.Range("A1").Resize(n, 15) = arOut
MsgBox "Done in " & Format(Timer - t0, "0.0 secs")
' or with duplicates to sheet2
For r = 3 To iLastRow
key = Trim(arIn(r, 2))
n = dict(key)
Sheet2.Cells(r, 2) = key
For c = 3 To 16
Sheet2.Cells(r, c) = arOut(n, c - 1)
Next
Next
End Sub

This assumes the data is on Sheet1 starting in A1.
Not sure how efficient it is.
Option Explicit
Sub Test()
Dim rngDst As Range
Dim dicIDs As Object
Dim dicData As Object
Dim arrData As Variant
Dim arrCols As Variant
Dim idxRow As Long
Dim idxCol As Long
Dim ky As Variant
Dim fld As Variant
Dim cnt As Long
With Sheets("Sheet1").Range("A1").CurrentRegion
arrCols = .Rows(1).Value
arrData = .Offset(1).Resize(.Rows.Count - 1).Value
End With
Set dicIDs = CreateObject("Scripting.Dictionary")
For idxRow = LBound(arrData, 1) To UBound(arrData, 1)
ky = arrData(idxRow, 1)
If dicIDs.exists(ky) Then
Set dicData = dicIDs(ky)
cnt = cnt + 1
Else
Set dicData = CreateBlankDic(arrCols)
End If
For idxCol = LBound(arrData, 2) To UBound(arrData, 2)
fld = arrCols(1, idxCol)
If arrData(idxRow, idxCol) <> "" Then
dicData(fld) = arrData(idxRow, idxCol)
End If
Next idxCol
Set dicIDs(ky) = dicData
Next idxRow
Set rngDst = Sheets("Sheet1").Range("A1").Offset(, UBound(arrCols, 2) + 2)
rngDst.Resize(1, UBound(arrCols, 2)).Value = arrCols
Set rngDst = rngDst.Offset(1).Resize(cnt, UBound(arrCols, 2))
ReDim arrData(1 To cnt, 1 To UBound(arrCols, 2))
cnt = 1
For Each ky In dicIDs.keys
Set dicData = dicIDs(ky)
idxCol = 1
For Each fld In dicData.keys
arrData(cnt, idxCol) = dicData(fld)
idxCol = idxCol + 1
Next fld
cnt = cnt + 1
Next ky
rngDst.Value = arrData
End Sub
Function CreateBlankDic(arrKeys, Optional BlankVal = "") As Object
Dim dic As Object
Dim idxCol As Long
Set dic = CreateObject("Scripting.Dictionary")
For idxCol = LBound(arrKeys, 2) To UBound(arrKeys, 2)
dic(arrKeys(1, idxCol)) = BlankVal
Next idxCol
Set CreateBlankDic = dic
End Function

Related

Load array elements until value is found

I have an array loading column references from column C.
The user will enter the current month, e.g. March, then the array should load February column value "U" and January value "L", then the rest of my code will run.
How do I setup the array to stop after the value "L" is found?
Sub CopyData() 'with array
Dim wb1 As Workbook
Dim wkshtname As String
Dim colArray(1 To 5) As Variant
Dim i As Range, rng As Range
Dim lrow As Long, colcounter As Long, y As Long, retcol As Long, z As Long
Dim StartHere As String, x As String, col As String
Dim cell
Dim sht As Worksheet
Set wb1 = ThisWorkbook
wkshtname = "Retro-" & wb1.Sheets("Instructions").Range("B4").Value
StartHere = wb1.Sheets("Instructions").Range("B4")
lrow = wb1.Sheets("Member Prem.Pymts").Cells(Rows.Count, 1).End(xlUp).Row
If StartHere = "January" Then
MsgBox "No Retro Commissions to be posted", vbOKOnly
Exit Sub
End If
'delete sheet if it exists
For Each sht In wb1.Worksheets
If sht.Name = wkshtname Then
Application.DisplayAlerts = False
wb1.Sheets(wkshtname).Delete
Application.DisplayAlerts = True
End If
Next sht
With wb1
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = wkshtname
With .Sheets(wkshtname)
.Cells(1).Resize(1, 8).Value = Array("ID", "Last Name", "First Name", "Premium", "Commission Amt", "month for", "agent", "sheet row")
End With
'returns Paid in Month 30-150 day columns
col = Application.WorksheetFunction.Match(StartHere, wb1.Sheets("Lookups").Range("$A$1:$A$13"), 0)
z = 1
For retcol = 1 To 5
colArray(retcol) = wb1.Sheets("Lookups").Cells(col - z, 3)
z = z + 1
Next retcol
With .Sheets("Member Prem.Pymts") 'reference target sheet
y = 1
For colcounter = LBound(colArray, 1) To UBound(colArray, 1)
x = 4 'starting row number data is found on
For Each i In .Range(colArray(colcounter) & "4:" & colArray(colcounter) & lrow) 'loop through Member Prem.Payments column cells
If i.Value = StartHere Then
wb1.Sheets(wkshtname).Cells(Rows.Count, "A").End(xlUp).Offset(1, 0) = .Range("A" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "B").End(xlUp).Offset(1, 0) = .Range("B" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "C").End(xlUp).Offset(1, 0) = .Range("C" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "D").End(xlUp).Offset(1, 0) = .Range("BR" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "E").End(xlUp).Offset(1, 0) = wb1.Sheets("Commissions to Pay").Range(wb1.Sheets("Lookups").Cells(col - y, 4) & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "F").End(xlUp).Offset(1, 0) = .Range(colArray(colcounter) & "2")
wb1.Sheets(wkshtname).Cells(Rows.Count, "G").End(xlUp).Offset(1, 0) = .Range("DR" & x)
wb1.Sheets(wkshtname).Cells(Rows.Count, "H").End(xlUp).Offset(1, 0) = x
End If
x = x + 1
Next
y = y + 1
Next colcounter
End With
End Sub
This is what is stored in the array when I run the code.
I'm trying to load the array and then the array needs to stop loading after the value is "L".
The array will never have more than 5 elements.
EDIT: Stripped down to the core problem for testing
Sub CopyData()
Dim rngMonths As Range, c As Range, wb1
Dim colArray(), StartHere, col, retcol As Long
Set wb1 = ActiveWorkbook
Set rngMonths = wb1.Sheets("Lookups").Range("A2:A13") 'month lookup range
StartHere = "March" 'for testing
col = Application.Match(StartHere, rngMonths, 0)
If Not IsError(col) Then
Set c = rngMonths.Cells(col)
ReDim colArray(1 To 5) '<<<<<<<<<<<<
For retcol = 1 To 5
colArray(retcol) = c.Offset(0, 2).Value 'col C value
If colArray(retcol) = "L" Then Exit For 'exit if Col C="L"
Set c = c.Offset(-1) 'next cell up
Next retcol
ReDim Preserve colArray(1 To retcol) '<<<<<resize array
Debug.Print Join(colArray, ",")
Else
MsgBox "No month match!", vbExclamation
Exit Sub
End If
End Sub

VBA - Create array of unique values and sum corresponding values

Im looking for some help with a VBA problem I'm having. Basically, I'm collecting information from a source file on sheet1 into static arrays. From those static arrays I'm creating a dynamic array with account numbers, and a calculated value. What I'm trying to do next is create a second dynamic array with only unique account numbers and summing the calculated values in the previous dynamic array. But I have no idea how to do that...
The following is what I have so far.
Dim ClosingCash() As Variant, MarginExcess() As Variant, VarMarg() As Variant, Acct() As Variant, FX() As Variant, UniqueAcct() As Variant, Answers() As Variant
Dim Dim1 As Long, Counter As Long, W_Sum As Long
Sheet1.Activate
Acct = Range("b2", Range("b2").End(xlDown))
ClosingCash = Range("f2", Range("f2").End(xlDown))
MarginExcess = Range("j2", Range("J2").End(xlDown))
FX = Range("n2", Range("n2").End(xlDown))
VarMarg = Range("o2", Range("o2").End(xlDown))
Dim1 = UBound(ClosingCash, 1)
ReDim Answers(1 To Dim1, 1 To 2)
For Counter = 1 To Dim1
Answers(Counter, 1) = Acct(Counter, 1)
Answers(Counter, 2) = (WorksheetFunction.Min(ClosingCash(Counter, 1) + VarMarg(Counter, 1), MarginExcess(Counter, 1)) * FX(Counter, 1))
Next Counter
Sheet3.Activate
Range("a2", Range("a2").Offset(Dim1 - 1, 1)).Value = Answers
What I would like to print out are the unique account numbers, and the sum of Answers(counter, 2) that correspond to that account number, similar to a SumIf.
Any advise would be greatly appreciated!
Sum Unique
In your code you could use it like this:
Dim Data As Variant: Data = getUniqueSum(Answers)
If Not IsEmpty(Data) Then
Sheet3.Range("E2").Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
End If
The Code
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Writes the unique values from the first column of a 2D array
' and the sum of the corresponding values in its second column,
' to a 2D one-based two-columns array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getUniqueSum( _
Data As Variant) _
As Variant
If IsEmpty(Data) Then Exit Function
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
Dim Key As Variant
Dim i As Long
Dim c1 As Long: c1 = LBound(Data, 2)
Dim c2 As Long: c2 = c1 + 1
For i = LBound(Data, 1) To UBound(Data, 1)
Key = Data(i, c1)
If Not IsError(Key) Then
If Len(Key) > 0 Then
.Item(Key) = .Item(Key) + Data(i, c2)
End If
End If
Next i
If .Count = 0 Then Exit Function
Dim Result As Variant: ReDim Result(1 To .Count, 1 To 2)
i = 0
For Each Key In .Keys
i = i + 1
Result(i, 1) = Key
Result(i, 2) = .Item(Key)
Next Key
getUniqueSum = Result
End With
End Function
Try This
Sub GetUniqueSum()
Dim Rng As Range
Dim numRows As Long, endRow As Long, outputRow As Long, i As Long
Dim rangeText As String
Dim acct As Variant
Dim Sum As Double, ClosingCash As Double, MarginExcess As Double
Dim FX As Double, VarMarg As Double
Dim Value As Double, Value2 As Double
'Get the last row as a string
numRows = Range("B2", Range("b2").End(xlDown)).Rows.Count
endRow = CStr(numRows + 1)
rangeText = "B2:O" & endRow
'Sort the range
Set Rng = Range("Sheet2!" & rangeText)
Rng.Sort (Rng.Columns(1))
'Initialize variables
acct = Rng.Cells(2, 1)
outputRow = 1
Sum = 0
'Calculate Sums
For i = 1 To Rng.Rows.Count
If Rng.Cells(i, 1) <> acct Then
'No longer same acct, print out results
outputRow = outputRow + 1
Worksheets("Sheet3").Cells(outputRow, 1) = acct
Worksheets("Sheet3").Cells(outputRow, 2) = Sum
acct = Rng.Cells(i, 1)
Sum = 0
End If
ClosingCash = Rng(i, 5).Value
MarginExcess = Rng(i, 9).Value
FX = Rng(i, 13).Value
VarMarg = Rng(i, 14).Value
Value = ClosingCash + VarMarg
Value2 = MarginExcess * FX
If Value > Value2 Then Value = Value2
Sum = Sum + Value
Next
'Print out last result
Worksheets("Sheet3").Cells(outputRow + 1, 1) = acct
Worksheets("Sheet3").Cells(outputRow + 1, 2) = Sum
End Sub

How to create a 3 dimensional array and then pull info 1 dimension at a time?

I would like to take data sets from Sheet 1 and fill in table values in Sheet 2. I believe using a multidimensional array to be the optimum way of accomplishing this.
Sheet 1 is setup as such:
Column A = "Dates", Column C = "SNs", Column E = "M0s", and Column F = "HNs".
An operator enters in an M0 value, and if a ("E").Row has that value, I want that row's SN, HN, and Date to be entered into Sheet 2. Just because two rows have the same M0 doesn't mean they have the same SN, HN, or Date. I would like each row's values to be stored separately, hence a multidimensional array (3 dimensional in this case).
The code below is my successful attempt at storing all SNs in an single dimensional array (based on M0 entered) and then entering those values into Sheet 2.
Sub FillSheet2()
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long 'could be substituted with Variant or String
ReDim varSNarray(0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray)) = SNcell
ReDim Preserve varSNarray(UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 99 Then
Set ws2range = ws2.Range("AA6:AA55")
ws2SNcellnum = i - 94
ws2.Range("AA" & ws2SNcellnum).Value = varSNarray(i)
ElseIf i > 49 Then
Set ws2range = ws2.Range("N6:N55")
ws2SNcellnum = i - 44
ws2.Range("N" & ws2SNcellnum).Value = varSNarray(i)
Else
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
End If
Next i
End Sub
I would like to add HN and Date along with SN as this sub runs. I don't know how to augment the array to allow for HN and Date storage though. Below is how I imagine it would look like. However, I cannot successfully create my array. I'm fairly sure it has something to do with my variable setups.
Dim varSNarray As Variant
Dim M0cell As Range
Dim SNcell As Long
Dim HNcell As Long
Dim Datecell As Long
ReDim varSNarray(0, 0, 0)
For Each M0cell In ws.Range("E7:E200000").Cells
If M0cell.Value <> vbNullString Then
If M0cell.Value = varPrintM0 Then
SNcell = ws.Range("C" & M0cell.Row).Value
varSNarray(UBound(varSNarray), HNcell, Datecell) = SNcell
varSNarray(SNcell, UBound(varSNarray), Datecell) = HNcell 'Script out of range error
varSNarray(SNcell, HNcell, UBound(varSNarray)) = Datecell
ReDim Preserve varSNarray(UBound(varSNarray) + 1, UBound(varSNarray) + 1, UBound(varSNarray) + 1) As Variant
End If
End If
Next M0cell
ReDim Preserve varSNarray(UBound(varSNarray) - 1)
Dim i As Long
For i = LBound(varSNarray) To UBound(varSNarray)
Dim ws2range As Range
Dim ws2SNcellnum As Long
If i > 149 Then
Set ws2range = ws2.Range("AN6:AN55")
ws2SNcellnum = i - 144
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("AN" & ws2SNcellnum).Value = varSNarray(Datecell)
''''
Removed this section has its the same as above
''''
Set ws2range = ws2.Range("A6:A55")
ws2SNcellnum = i + 6
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(i)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(HNcell)
ws2.Range("A" & ws2SNcellnum).Value = varSNarray(Datecell)
End If
Next i
How do I store data into a 3 dimensional array and then successful pull 1 dimension from the array at a time?
I don't think an array is necessary here, just write the records to Sheet 2 as they are found. For example
Option Explicit
Sub FillSheet2()
Const COL_DATE = "A"
Const COL_SN = "C"
Const COL_M0 = "E"
Const COL_HN = "F"
Const START_ROW = 7
' target sheet
Const TARGET_START_ROW = 5
Const TARGET_START_COL = 1 'A
Const COL_REPEAT = 13 ' N, AA, AN
Const MAX_ROWS = 50
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Sheets("Sheet1")
Set wsTarget = wb.Sheets("Sheet2")
wsTarget.Cells.Clear
Dim iRow As Integer, iLastRow As Integer, iCount As Integer
Dim iTargetRow As Integer, iTargetCol As Integer, sM0 As String
Dim varPrintM0 As String
iTargetCol = TARGET_START_COL
iTargetRow = TARGET_START_ROW
varPrintM0 = "Test4"
iCount = 0
iLastRow = wsSource.Range(COL_M0 & Rows.Count).End(xlUp).Row
' ----------
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
.Offset(0, 0) = wsSource.Range(COL_SN & iRow).Value
.Offset(0, 1) = wsSource.Range(COL_HN & iRow).Value
.Offset(0, 2) = wsSource.Range(COL_DATE & iRow).Value
End With
iTargetRow = iTargetRow + 1
If iTargetRow >= MAX_ROWS + TARGET_START_ROW Then
iTargetCol = iTargetCol + COL_REPEAT
iTargetRow = TARGET_START_ROW
End If
iCount = iCount + 1
End If
Next
End With
MsgBox iCount & " rows copied", vbInformation, "Finished"
' --------
End Sub
If you do want to use an array replace the code between the ------ lines above with this
Dim ar(5, 50, 3) As Variant ' max of 5 blocks of 50 records
Dim t As Integer, r As Long
t = 1: r = 1
' fill array
With wsSource
For iRow = START_ROW To iLastRow
sM0 = .Range(COL_M0 & iRow)
If sM0 = varPrintM0 Then
With wsTarget.Cells(iTargetRow, iTargetCol)
ar(t, r, 0) = sM0
ar(t, r, 1) = wsSource.Range(COL_SN & iRow).Value
ar(t, r, 2) = wsSource.Range(COL_HN & iRow).Value
ar(t, r, 3) = wsSource.Range(COL_DATE & iRow).Value
End With
r = r + 1
If r > MAX_ROWS Then
r = 1
t = t + 1
End If
iCount = iCount + 1
End If
Next
End With
' output array
Dim iLastTable As Long, c As Long
iLastTable = t
For t = 1 To iLastTable
For r = 1 To 50
c = 1 + COL_REPEAT * (t - 1)
With wsTarget.Cells(r + 4, c)
.Offset(0, 0) = ar(t, r, 1)
.Offset(0, 1) = ar(t, r, 2)
.Offset(0, 2) = ar(t, r, 3)
End With
Next r
Next t
MsgBox iCount & " rows copied using Array", vbInformation, "Finished"

Loop to return an array when row number and array number does not match. Problems with nested loop

I have a problem where I have created an Array with variables and I want to enter the values in my Array in a separate column which does not match the row index of my Array.
I want to loop through a column and I want to return a value from an Array which does not correspend with the row index of the column. That could for example be to return the first value of my Array on the sixth row.
I Think that my problem probably lies in that I don't know how to set up the nested loop.
Many thanks for any help
I have created my Array like this
Sub arraytest()
Dim MonthArray() As String
Dim Lastrow As Long
Dim StartRow As Byte
StartRow = 2
Dim r As Byte
Lastrow = Range("B" & StartRow).CurrentRegion.Rows.count
If Lastrow > 0 Then
ReDim MonthArray(StartRow To Lastrow)
For r = StartRow To Lastrow
MonthArray(r) = Range("C" & r).Value
Next r
End If
End Sub
So if I have the values in my Array
MonthArray()
Month 1
Month 2
Month 3
Month 4
Month 5
Month 6
Then a simple loop without taking into account row index would be
For i = StartRow To Lastrow
If (Cells(i, "A").Value = "USA:" or Cells(i, "A").Value = "EU:") Then _
Cells(i, "B").Value = " " Else Cells(i, "B").Value = MonthArray(i) <<<
Next i
This would return a table in this order
1 USA:
2 Data MonthArray(2)
3 Data MonthArray(3)
4 EU:
5 Data MonthArray(5)
6 Data MonthArray(6)
But I need the array to be returned like this:
1 USA:
2 Data MonthArray(1)
3 Data MonthArray(2)
4 EU:
5 Data MonthArray(3)
6 Data MonthArray(4)
So, in this case, I want to add the value from my Array if the value in the A column is not USA or EU
What I have tried is this
r = 1
For i = StartRow To Lastrow
If (Cells(i, "A").Value = "USA" or Cells(i, "A").Value = "EU") Then _
Cells (i, "B").Value = " " Next i Else Cells(i, "B").Value = MonthArray (r) <<<
r = r + 1
Next i
However, I want
r = r + 1
To occur only if (Cells(i, "A").Value = "USA" or Cells(i, "A").Value = "EU")
Any help is highly appreciated
If you have a contiguous range for your MonthArray, don't worry about looping and just use:
Dim MonthArray() As Variant, StartRow as Long, LastRow as Long
StartRow = 2
Lastrow = Cells(StartRow, "B").CurrentRegion.Rows.count
MonthArray = Range(Cells(StartRow, "C"), Cells(LastRow, "C")).Value
Then we move into using the array, like your code indicates:
Dim r as Long, i as Long
r = 1
For i = StartRow To Lastrow
If UCase(Cells(i, "A").Value) = "USA" or UCase(Cells(i, "A").Value) = "EU" Then
Cells(i, "B").Value = " "
Else
Cells(i, "B").Value = MonthArray(r,1)
r = r + 1
End If
Next i
Need your r = r+1 in the loop as you move down.
Edit1:
Make sure to add in Sheet references. Assumption made from my testing, where I don' want to be overwriting my cells in B if I determine LastRow based on col B, e.g.:
With Sheets("MonthSource")
Dim MonthArray() As Variant, StartRow as Long, LastRow as Long
StartRow = 2
Lastrow = .Cells(StartRow, "B").CurrentRegion.Rows.count
MonthArray = .Range(.Cells(StartRow, "C"), .Cells(LastRow, "C")).Value
End With
With Sheets("Destination")
Dim r as Long, i as Long
r = 1
For i = StartRow To Lastrow
If UCase(.Cells(i, "A").Value) = "USA" or UCase(.Cells(i, "A").Value) = "EU" Then
.Cells(i, "B").Value = " "
Else
.Cells(i, "B").Value = MonthArray(r,1)
r = r + 1
End If
Next i
End With
Something like this should work for you:
Sub tgr()
Dim ws As Worksheet
Dim MonthArray() As Variant
Dim StartRow As Long
Dim LastRow As Long
Dim i As Long, r As Long
'Always fully qualify workbook and worksheet you're working with, change this as necessary
Set ws = ActiveWorkbook.ActiveSheet
StartRow = 2
LastRow = ws.Cells(StartRow, "B").CurrentRegion.Rows.Count
'Load the values of column C into an array directly, no loop required
With ws.Range(ws.Cells(StartRow, "C"), ws.Cells(LastRow, "C"))
If .Row < StartRow Then Exit Sub 'No data
If .Cells.Count = 1 Then
'Only a single value found in column C, force array type by manually redimming and adding the value
ReDim MonthArray(1 To 1, 1 To 1)
MonthArray(1, 1) = .Value
Else
'Multiple values found in column C, can insert values into array directly
MonthArray = .Value
End If
End With
'Initialize your array index counter variable at 0 to start
r = 0
'Begin loop of rows
For i = StartRow To LastRow
'Check contents of column A
Select Case UCase(Trim(ws.Cells(i, "A").Value))
Case "USA:", "EU:"
'do nothing
Case Else
'increase array index counter variable
r = r + 1
'Output the appropriate array value to column B
ws.Cells(i, "B").Value = MonthArray(r, 1)
End Select
Next i 'advance row counter
End Sub

Match 2D arrays and output values of another array

I cannot get to work condition for matching 2D arrays. I have tried another approach and this one is closer to the solution, but still does not produce the outcome.
This is what I want to do:
In sheet1 I have different dates that go through columns and size is uncertain. Below these dates are the values:
In sheet 2, I have a smaller subset of dates (that should exist in sheet1):
Through the code, I want to match the dates in sheet1 and sheet2, and only if match is true, I want to write the corresponding values from sheet1 to sheet2.
This is the outcome:
I want to use Arrays for dates in sheet1 and sheet2 and if they match, write the array of values. But the arrays of dates turn to be empty and so condtion for match does not work. I am not getting any error message as well:
Sub test()
Dim arrAmounts() As Variant
Dim arrDates_w2() As Variant
Dim arrDates_w1() As Variant
Dim Lastcol_w2 As Integer
Dim Lastcol_w1 As Integer
Dim LastRow As Integer
Dim i As Integer
Dim w As Integer
Dim d As Integer
Dim f As Integer
Dim g As Integer
Dim w1 As Worksheet
Dim w2 As Worksheet
Set w1 = Sheets("Sheet1")
Set w2 = Sheets("Sheet2")
LastRow = 17 'last row on both sheets
f = 1
g = 1
With w2
Lastcol_w2 = .Cells(3, Columns.Count).End(xlToLeft).Column
'array of dates in w2
ReDim arrDates_w2(1, Lastcol_w2)
End With
With w1
Lastcol_w1 = .Cells(3, Columns.Count).End(xlToLeft).Column
'Assign arrays:
ReDim arrAmounts(LastRow, Lastcol_w1)
ReDim arrDates_w1(1, Lastcol_w1)
For i = 1 To LastRow
For d = 1 To UBound(arrDates_w1, 2)
arrAmounts(i, d) = .Cells(3 + i, 2 + d)
Next
Next
'Match the dates in worksheets 1 and 2
For i = 1 To LastRow
For w = 1 To UBound(arrDates_w2, 2)
For d = 1 To UBound(arrDates_w1, 2)
If arrDates_w2(1, w) = arrDates_w1(1, d) Then
w2.Cells(i + 3, 2 + w) = arrAmounts(i, f + 3)
End If
Next
Next
Next
End With
End Sub
I would appreciate suggestions.
Please try this code.
Option Explicit
Sub CopyColumns()
Const CaptionRow As Long = 3 ' on all sheets
Const FirstClm As Long = 3 ' on all sheets
Dim WsIn As Worksheet ' Input sheet
Dim WsOut As Worksheet ' Output sheet
Dim DateRange As Range ' dates on WsIn
Dim Cin As Long ' input column
Dim Rl As Long ' last row in WsIn
Dim Cl As Long ' last used column in WsOut
Dim C As Long ' column counter in WsOut
Dim Arr As Variant ' transfer values
Set WsIn = Worksheets("Sheet1")
Set WsOut = Worksheets("Sheet2")
With WsIn
Set DateRange = .Range(.Cells(CaptionRow, FirstClm), .Cells(CaptionRow, .Columns.Count).End(xlToLeft))
End With
With WsOut
Cl = .Cells(CaptionRow, .Columns.Count).End(xlToLeft).Column
For C = FirstClm To Cl
On Error Resume Next
Cin = Application.Match(.Cells(CaptionRow, C).Value2, DateRange, 0)
If Err = 0 Then
Cin = Cin + DateRange.Column - 1
Rl = WsIn.Cells(WsIn.Rows.Count, Cin).End(xlUp).Row
Arr = WsIn.Range(WsIn.Cells(CaptionRow + 1, Cin), WsIn.Cells(Rl, Cin)).Value
.Cells(CaptionRow + 1, C).Resize(UBound(Arr)).Value = Arr
End If
Next C
End With
End Sub
What do you expect ReDim arrDates_w2(1, Lastcol_w2) to be doing? As it stands, it's only re-sizing the number of items that can be held in the array... You need to assign the Range to it: arrDates_w2 = w2.Range("C3:K3").Value for example. This will create a multi-dimensional array.
Then you can loop the items. Here's some sample code to illustrate the principle
Sub GetArrayInfo()
Dim a As Variant, i As Long, j As Long
Dim w2 As Worksheet
Set w2 = Sheets("Sheet2")
a = ws.Range("C3:K3").Value2
Debug.Print UBound(a, 1), UBound(a, 2)
For j = 1 To UBound(a, 2)
For i = 1 To UBound(a, 1)
Debug.Print a(i, j)
Next
Next
End Sub
Try
Sub test()
Dim Ws As Worksheet, Ws2 As Worksheet
Dim c As Integer, j As Integer, p As Integer
Dim i As Long, r As Long
Dim arr1() As Variant, arr2() As Variant
Dim rngDB As Range, rngHead As Range
Set Ws = Sheets("Sheet1")
Set Ws2 = Sheets("Sheet2")
With Ws
c = .Cells(3, Columns.Count).End(xlToLeft).Column
r = .Range("c" & Rows.Count).End(xlUp).Row
Set rngHead = .Range("c3", .Cells(3, c))
arr1 = .Range("c3", .Cells(r, c))
End With
With Ws2
c = .Cells(3, Columns.Count).End(xlToLeft).Column
Set rngDB = .Range("c3", .Cells(r, c))
arr2 = rngDB
End With
For j = 1 To UBound(arr2, 2)
p = WorksheetFunction.Match(arr2(1, j), rngHead, 0)
For i = 2 To UBound(arr2, 1)
arr2(i, j) = arr1(i, p)
Next i
Next j
rngDB = arr2
End Sub

Resources