Finding Overlap counts - excel

Hi I have 2 columns (cities and members) with 5 unique cities and 100,000 members. Some members may be assigned to multiple cities. I would like a graph that has 6 columns and the 6 rows of the cities (with additional No City Assigned Column). The values in the table would be the member counts. So I'm basically trying to count overlap. How can I accomplish this?
I wish it would be as simple as dragging my cities field into both columns and rows in the pivot table but I can't.
I would like it to look like this:

Assuming you want conditional formatting:
Select the full range you want to apply the formatting to. Then apply a rule (formula option) so that =B$1=$A2 (assuming your have selected from B2 to some end). The use of the fixed ("$") condition on column or row helps determine that this applies to each cell in the selected range individually.

Here's a VBA solution. Set up a working array with one row for each distinct member, one column for each distinct city, and fill with 1's where member and city coincide. Then transfer into output array where pairs of columns in working array have been set to 1:
Option Explicit
Sub MultResponse()
Dim LastRow, LastColumn As Long
Dim sht1, sht2 As Worksheet
Dim workArray() As Integer
Dim cityDict As New Scripting.Dictionary
Dim memberDict As New Scripting.Dictionary
Dim city, member As String
Dim item As Integer
Dim i, j As Long
Dim memberNo As Long
Dim cityNo As Integer
Dim outputArray() As Integer
Dim outrow, outcol, rowTotal As Integer
Set sht1 = ThisWorkbook.Worksheets("Sheet1")
Set sht2 = ThisWorkbook.Worksheets("Sheet2")
LastRow = sht1.Cells(sht1.Rows.Count, "A").End(xlUp).Row
' Make list of distinct cities
j = 0
For i = 2 To LastRow
city = sht1.Cells(i, 2)
If city <> "" And Not cityDict.Exists(city) Then
j = j + 1
cityDict.Add Key:=city, item:=j
End If
Next i
' Make list of distinct members
j = 0
For i = 2 To LastRow
member = sht1.Cells(i, 1)
If member <> "" And Not memberDict.Exists(member) Then
j = j + 1
memberDict.Add Key:=member, item:=j
End If
Next i
' Set up and fill array with one row for each distinct member, one column for each distinct city
ReDim workArray(1 To memberDict.Count, 0 To cityDict.Count)
For i = 2 To LastRow
member = sht1.Cells(i, 1)
city = sht1.Cells(i, 2)
If city <> "" And member <> "" Then
memberNo = memberDict(member)
cityNo = cityDict(city)
workArray(memberNo, cityNo) = 1
End If
Next i
' Fill output array where pairs of columns in work array are set to 1
' outputArray(0,0) is used for members with missing city
ReDim outputArray(0 To cityDict.Count, 0 To cityDict.Count)
'First do ones with no affiliation
For i = 1 To memberDict.Count
rowTotal = 0
For j = 1 To cityDict.Count
rowTotal = rowTotal + workArray(i, j)
Next j
If rowTotal = 0 Then outputArray(0, 0) = outputArray(0, 0) + 1
Next i
' Then do ones with affiliation
For outrow = 1 To cityDict.Count
For outcol = 1 To cityDict.Count
For i = 1 To memberDict.Count
If workArray(i, outrow) = 1 And workArray(i, outcol) = 1 _
Then outputArray(outrow, outcol) = outputArray(outrow, outcol) + 1
Next i
Next outcol
Next outrow
' Transfer output array into sheet
For i = 0 To cityDict.Count
For j = 0 To cityDict.Count
sht2.Cells(i + 2, j + 2) = outputArray(i, j)
Next j
Next i
'Insert row and column headers
sht2.Cells(1, 2) = "N/C"
sht2.Cells(2, 1) = "N/C"
For i = 0 To cityDict.Count - 1
sht2.Cells(i + 3, 1) = cityDict.Keys(i)
Next i
For j = 0 To cityDict.Count - 1
sht2.Cells(1, j + 3) = cityDict.Keys(j)
Next j
End Sub
Test data
Results

Related

Visual basic copy and paste in excel is very slow

I have sheet which contains lots of column data, first column is date one in second column there are quantities and in the third one there are codes of item :
the data looks like this :
date qty code qty code
01.01.2022 0 4355 2 4356
02.01.2022 0 4355 2 4356
03.01.2022 0 4355 2 4356
....................................
and I want to have like this :
date qty code
01.01.2022 0 4355
02.01.2022 0 4355
03.01.2022 0 4355
01.01.2022 2 4356
02.01.2022 2 4356
03.01.2022 2 4356
I wrote the code in visual basic for macro which cuts fourth and fifth columns pasts at the end of second and third columns and then deletes empty columns and continuous until there are no empty columns my code works but it takes hours to execute on 1000+ columns and I want to know if there is any possible way to optimize it.
code:
Sub CutAndPasteColumnsUntilEmpty()
Dim lastRow As Long
Dim i As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
Do Until IsEmpty(Range("D2")) And IsEmpty(Range("E2"))
Range("D2:D" & lastRow).Cut Destination:=Range("B" & lastRow + 1)
Range("E2:E" & lastRow).Cut Destination:=Range("C" & lastRow + 1)
lastRow = ActiveSheet.UsedRange.Rows.Count
Columns("D:E").Delete
Loop
End Sub
This routine doesn't copy/paste any data.
It reads your table into an array, then creates a new array from that input array in the format you want. It then creates a new tab and writes the output to that tab. It should take seconds, not hours.
This will output by reading each row at a time.
Sub ReorganiseTable()
'Declarations
Dim LastRow As Long
Dim LastColumn As Long
Dim NoOfRows As Long
Dim NoOfColumnSets As Long
Dim o As Long, r As Long, c As Long
With ActiveSheet
'Find Last Row of table
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
NoOfRows = LastRow - 1
'Find Last Column of table
LastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
NoOfColumnSets = (LastColumn - 1) / 2
'Copy table to array
Dim ArrInput
ArrInput = ActiveSheet.Range(ActiveSheet.Cells(1, 1), ActiveSheet.Cells(LastRow, LastColumn)).Value
'Create output array for filling
ReDim ArrOutput(1 To NoOfColumnSets * NoOfRows + 1, 1 To 3)
'Copy headers across
ArrOutput(1, 1) = ArrInput(1, 1)
ArrOutput(1, 2) = ArrInput(1, 2)
ArrOutput(1, 3) = ArrInput(1, 3)
'Copy data across order by rows,columns
o = 2
For r = 2 To LastRow
For c = 2 To LastColumn Step 2
ArrOutput(o, 1) = ArrInput(r, 1)
ArrOutput(o, 2) = ArrInput(r, c)
ArrOutput(o, 3) = ArrInput(r, c + 1)
o = o + 1
Next
Next
End With
'Create a new tab
Worksheets.Add
'Write output array to tab
ActiveSheet.Cells(1, 1).Resize(UBound(ArrOutput), 3).Value = ArrOutput
End Sub
If you'd prefer it ordered by reading each column set at a time, invert the two For statements:
'Copy data across order by rows,columns
o = 2
For c = 2 To LastColumn Step 2
For r = 2 To LastRow
ArrOutput(o, 1) = ArrInput(r, 1)
ArrOutput(o, 2) = ArrInput(r, c)
ArrOutput(o, 3) = ArrInput(r, c + 1)
o = o + 1
Next
Next
This is one of those occasions when the OP may be reaching for VBA too soon. The task can also be achieved via spreadsheet functions (if the Excel version is recent enough):
The formula in cell G2 is:
=LET(n,COUNTA(A:A)-1,arr,OFFSET(A2:E2,0,0,n),r,SEQUENCE(n*2),c,SEQUENCE(,3),IF(r>n,INDEX(arr,r-n,IF(c>1,c+2,c)),INDEX(arr,r,c)))
The LET function allows you to do intermediate calculations and store the result in a variable.
n = number of rows in the input data
arr = input array (resized from first row in data, for n rows)
r = a vector of rows (1 .. 2n) in the output table
c = a vector of columns (1 .. 3) in the output table
The final parameter is the calculation, which takes columns (1,2,3) from the input for the first n rows of the output table, and thereafter takes columns (1,4,5) for rows n+1 to 2n.
This has the benefits that the sheet can remain a .xlsx file (and hence avoid security warnings) and the output columns will update automatically (with calc set to auto) as new data is added to the input. It will also be faster than VBA.
Stack Columns
It looks like it's written for any number of columns (Cols, Current) but it isn't (too lazy).
It only works for stacking column pairs to the first column.
The total number of columns is supposed to be odd (first + even).
It also includes the headers.
=LET(Data,A1:K7,Cols,2,
Current,TAKE(Data,,1+Cols),First,DROP(TAKE(Data,,1),1),Other,DROP(Data,1,1+Cols),
rCount,ROWS(First),cCount,COLUMNS(Other),cCountHalf,rCount*cCount/Cols,
SeqFirst,MOD(SEQUENCE(cCountHalf)-1,rCount)+1,
SeqOther,Cols*ROUNDUP(SEQUENCE(cCountHalf,,,Cols)/(Cols*rCount),0)-1,
VSTACK(Current,HSTACK(INDEX(First,SeqFirst),
INDEX(Other,SeqFirst,SeqOther),INDEX(Other,SeqFirst,SeqOther+1))))
Regarding to CLRs solution i would like to show my additional variant. With this one you can vary the columnsets as you wish.
Sub ReorganizeTable()
Dim arrA As Variant
Dim arrB As Variant
Dim c As Long
Dim r As Long
Dim isFirstRun As Boolean
Dim ColumnSet As Long
Dim RowSet As Long
Dim maxCols As Long
Dim maxRows As Long
Dim maxSets As Long
Dim ToggleCol As Integer
ColumnSet = 3 'set your columns here
With Cells(1, 1).CurrentRegion 'get dimension and array
maxRows = .Rows.Count - 1 '-1 = remove headers if available
maxCols = .Columns.Count
arrA = .Offset(1, 0).Resize(maxRows, maxCols)
End With
maxSets = maxCols / ColumnSet
ReDim arrB(1 To maxRows * maxSets, 1 To ColumnSet)
isFirstRun = True
For c = 0 To maxCols - 1 'must not start with 1, see ToggleCol below
ToggleCol = c Mod ColumnSet + 1 'switches between 1 and 2 but has to start with 1
If Not isFirstRun Then
If ToggleCol = 1 Then
RowSet = RowSet + maxRows
End If
End If
For r = 1 To maxRows
arrB(r + RowSet, ToggleCol) = arrA(r, c + 1)
Next
isFirstRun = False
Next
Range("...").Resize(UBound(arrB, 1), UBound(arrB, 2)) = arrB 'set your outputrange here
End Sub
Add one line: Application.ScreenUpdating = False
Sub CutAndPasteColumnsUntilEmpty()
Dim lastRow As Long
Dim i As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
Application.ScreenUpdating = False
Do Until IsEmpty(Range("D2")) And IsEmpty(Range("E2"))
Range("D2:D" & lastRow).Cut Destination:=Range("B" & lastRow + 1)
Range("E2:E" & lastRow).Cut Destination:=Range("C" & lastRow + 1)
lastRow = ActiveSheet.UsedRange.Rows.Count
Columns("D:E").Delete
Loop
End Sub

vba how to select a set of rows based on multiple column

Please help
I am trying to perform the following:
I have an excel file 'A' with 50000 rows.
I am creating another excel 'B' with 150 rows.
The 150 rows are picked from file 'A'.
The row selection criteria is based on values of 5 different columns as this set
First I want to make sure I select the rows with all different combination of these 5 columns
If I run out of combinations then I can pick combination which are repeated as have to reach the 150
What I have achieved till now is selecting 150 random rows from excel A and pasted in excel B
records = 150
With DataWs
SourceLastRow = .Cells(.Rows.count, "B").End(xlUp).Row
.Rows(1).Copy DestinationWs.Cells(DestLastRow, "A")
ar = RandomNumber(2, SourceLastRow, Records)
For r = 2 To UBound(ar)
DestLastRow = DestLastRow + 1
.Rows(ar(r)).Copy DestinationWs.Cells(DestLastRow, "A")
Next r
End With
Function RandomNumber(Bottom As Long, Top As Long, Amount As Long) As Variant
Dim i As Long, r As Long, temp As Long
ReDim iArr(Bottom To Top) As Long
For i = Bottom To Top: iArr(i) = i: Next i
For i = 1 To Amount
r = Int(Rnd() * (Top - Bottom + 1 - (i - 1))) _
+ (Bottom + (i - 1))
temp = iArr(r): iArr(r) = iArr(Bottom + i - 1): _
iArr(Bottom + i - 1) = temp
Next i
ReDim Preserve iArr(Bottom To Bottom + Amount - 1)
RandomNumber = iArr
End Function
This is maybe a bit complex but worked for me:
Sub PickRows()
Const COPY_ROWS As Long = 150
Dim dict As Object, data, DataWS As Worksheet, DestWS As Worksheet
Dim numCopied As Long, r As Long, k As String, destRow As Long
Dim combo As Long, keys, col As Collection, theRow As Long, t
Set DataWS = Sheet2 'for example
Set DestWS = Sheet3 'for example
'get the source data (at least the part with the key columns) in an array
data = DataWS.Range("A1:E" & DataWS.Cells(DataWS.Rows.Count, "B").End(xlUp).Row).Value
Set dict = CreateObject("scripting.dictionary")
'fill the dictionary - keys are combined 5 columns, values are collection
' containing the row number for each source row with that key
For r = 2 To UBound(data, 1)
k = RowKey(data, r, Array(1, 2, 3, 4, 5)) 'combination of the 5 columns
If Not dict.exists(k) Then
dict.Add k, New Collection 'new combination?
End If
dict(k).Add r
Next r
numCopied = 0
combo = 0
destRow = 2
'loop over the various key column combinations and pick a row from each
' keep looping until we've copied enough rows
Do While numCopied < COPY_ROWS
'see here for why the extra ()
'https://stackoverflow.com/questions/26585884/runtime-error-with-dictionary-when-using-late-binding-but-not-early-binding
Set col = dict.Items()(combo) 'a collection of all rows for this particular key
theRow = RemoveRandom(col)
'edit line below to copy more columns (eg change 5 to 10)
DataWS.Cells(theRow, 1).Resize(1, 5).Copy DestWS.Cells(destRow, 1)
destRow = destRow + 1 'next destination row
If col.Count = 0 Then dict.Remove dict.keys()(combo) 'remove if no more rows for this key
If dict.Count = 0 Then Exit Do 'run out of any rows to pick? (should not happen...)
combo = combo + 1
If combo >= dict.Count Then combo = 0 'start looping again
numCopied = numCopied + 1
Loop
End Sub
'Create a composite key from columns in arrKeyCols
Function RowKey(data, rowNum, arrKeyCols) As String
Dim rv, i, sep
For i = LBound(arrKeyCols) To UBound(arrKeyCols)
rv = rv & sep & data(rowNum, arrKeyCols(i))
sep = "~~"
Next i
RowKey = rv
End Function
'select a random item from a collection, remove it, and return the value
Function RemoveRandom(col As Collection)
Dim rv, num As Long
num = Application.RandBetween(1, col.Count)
RemoveRandom = col(num)
col.Remove num
End Function

How can i use VBA Code to Copy and Paste Specific Cells if Condition is Met in two or more worksheets to different areas of another worksheet

Looking for a little more help please. I was here a month ago a RiskyPenguin gave me a great bit of code. I would like to add to this.
This is the part that works:
So if the "invoice" spreadsheet (sheet 5), if cell G4 (for example is I111) matches any of the data in the first column of the "income" spreadsheet (sheet 1) (starting at row 6) then the corresponding data in columns 2 3, 8 & 9 will copy over to the "invoice" spreadsheet in columns 2, 3, 4 & 5 (starting at row 13).
Sub FindAndCopyData2()
Dim shData As Worksheet, shReport As Worksheet
Set shData = Sheet1
Set shReport = Sheet6
Dim strInvoceNumber As String
strInvoceNumber = shReport.Cells(4, "E").Value
Dim intLastRow As Integer
intLastRow = shData.Cells(Rows.Count, 1).End(xlUp).Row
Dim intReportRow As Integer
intReportRow = 13
shReport.Range("B13:E20").ClearContents
Dim i As Integer
For i = 1 To intLastRow
If shData.Cells(i, 1).Value2 = strInvoceNumber Then
shReport.Cells(intReportRow, 2).Value2 = shData.Cells(i, 3).Value2
shReport.Cells(intReportRow, 3).Value2 = shData.Cells(i, 4).Value2
shReport.Cells(intReportRow, 4).Value2 = shData.Cells(i, 8).Value2
shReport.Cells(intReportRow, 5).Value2 = shData.Cells(i, 9).Value2
intReportRow = intReportRow + 1
End If
Next i
End Sub
I would then like to (hopefully using the same search)
Take the "invoice" spreadsheet (sheet 5), if cell G4 (for example is I111) matches any of the data in the second column of the "expenses" spreadsheet (sheet 2) (starting at row 11) then the corresponding data in columns 3, 5, & 7 will copy over to the "invoice" spreadsheet in columns 2, 4 & 6 (starting at row 13).
Is this possible or does it have to be a separate piece of programming?
Many Thanks for any advise.
Assuming this could be useful for others I made a function out of it and refactored the initial code to handle the copy in memory. I setup your first lookup so you just need to edit the variables to get your second lookup:
Option Explicit
''''''''''''''''''''''''''''''''''''''
''Main Sub
''''''''''''''''''''''''''''''''''''''''''''''''''
Sub main()
'Set some vars
Dim sourceArr, targetArr, sourceCls, targetCls, sourceStartRw As Long, targetStartRw As Long, dict As Object, j As Long, sourceLookupCl As Long, Matchkey As Long
''''''''''''''''''''''''''''''''''''''
''Lookup 1
''''''''''''''''''''''''''''''''''''''''''''''''''
Matchkey = Sheet5.Range("G4").Value2 'lookupKey
sourceCls = Split("2,3,8,9 ", ",") 'Columns to copy from
targetCls = Split("2,3,4,5", ",") 'Columns to copy to
sourceStartRw = 6
targetStartRw = 13
sourceLookupCl = 1 'matching column
'get data in memory = array
sourceArr = Sheet1.Range("A1").CurrentRegion.Value2
'call our function
targetArr = reorder(sourceArr, sourceCls, targetCls, sourceStartRw, sourceLookupCl, Matchkey)
'dump to sheet
With Sheet5
.Range(.Cells(targetStartRw, 1), .Cells(UBound(targetArr) + targetStartRw - 1, UBound(targetArr, 2))).Value2 = targetArr
End With
''''''''''''''''''''''''''''''''''''''
''Lookup 2 => change source and target cols to your need
''''''''''''''''''''''''''''''''''''''''''''''''''
Matchkey = Sheet5.Range("G4").Value2
sourceCls = Split("2,3,8,9 ", ",")
targetCls = Split("2,3,4,5", ",")
sourceStartRw = 6
targetStartRw = 13 'must be the same as previous lookup if you want to keep the targetArr from previous lookups
sourceLookupCl = 1
'get data in memory = array
sourceArr = Sheet1.Range("A1").CurrentRegion.Value2
'call our function keeping the data from the first lookup
targetArr = reorder(sourceArr, sourceCls, targetCls, sourceStartRw, sourceLookupCl, Matchkey, targetArr)
'dump to sheet
With Sheet5
.Range(.Cells(targetStartRw, 1), .Cells(UBound(targetArr) + targetStartRw - 1, UBound(targetArr, 2))).Value2 = targetArr
End With
End Sub
''''''''''''''''''''''''''''''''''''''
''Supporting function
''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function reorder(sourceArr, sourceCls, targetCls, sourceStartRw As Long, sourceLookupCl As Long, Matchkey As Long, Optional targetArr) As Variant
Dim dict As Object, j As Long
'if the target array overlaps the previous lookups pass it to the function
If IsMissing(targetArr) Then
ReDim targetArr(1 To UBound(sourceArr), 1 To UBound(sourceArr, 2))
End If
'build a dict to compare quickly
Set dict = CreateObject("Scripting.Dictionary") 'create dictionary lateB
For j = 1 To UBound(sourceArr) 'traverse source
dict(sourceArr(j, sourceLookupCl)) = Empty
Next j
'check if key exists in dict and copy data
Dim i As Long, ii As Long ': ii = 1
If dict.Exists(Matchkey) Then
For j = sourceStartRw To UBound(sourceArr)
For i = 1 To UBound(sourceArr, 2)
If i = sourceCls(ii) Then
targetArr(j - sourceStartRw + 1, targetCls(ii)) = sourceArr(j, i)
ii = IIf(ii < UBound(sourceCls), ii + 1, ii)
End If
Next i
ii = 0
Next j
End If
reorder = targetArr
End Function

Create a table with all potential combinations from a given list with two columns (excel)

Is there a way (vba code or excel trick) to manipulate a 2 columnar list so that I get a table with all potential combinations depending on a unique identifier in the first column?
E.g. I have one column with Company Names and another with Country Locations. What I need is every set if combinations of the countries per company (see screenshot attached).
This vba module should solve your problem.
Just copy the code to a new module, declare the input and output columns and the number of the first row of your list.
Note that the code will stop once it hits a line where the "Unique Identifier" Cell is empty.
Also, it requires that your list is sorted with respect to your "Unique Identifier".
If a Unique Identifier only appears once, it will still be written into the output list, but only once and with the outColNation2 staying empty in that row. If this is not desired and it should be left out entirely, just delete the commented if-statement.
Example Image of output
Also note, that a unique identifier can repeat at most 100 times. I assume none of them appears that often as that would create a ridiculously long output list.
Option Compare Text
Sub COMBINATIONS()
Dim i As Long, j As Long, k As Long, l As Long, n As Long
Dim arr(100) As String
Dim UI As String
Dim inColUI As Integer, inColNation As Integer
Dim outColUI As Integer, outColNation1 As Integer, outColNation2 As Integer
Dim FirstRowOfData As Integer
Dim YourWS As Worksheet
inColUI = 1 'Column of the "Unique Identifier"
inColNation = 2 'Column of the "Nations" in your example
outColUI = 4
outColNation1 = 5 'output columns
outColNation2 = 6
FirstRowOfData = 2 'First Row of data
Set YourWS = Application.Worksheets("Sheet1") 'Put in your Worksheet Name here.
i = FirstRowOfData
n = FirstRowOfData
With YourWS
Do Until .Cells(i, inColUI) = ""
j = 0
UI = .Cells(i, inColUI)
Do Until .Cells(i - 1, inColUI) <> .Cells(i, inColUI) And j > 0 Or .Cells(i, inColUI) = ""
arr(j + 1) = .Cells(i, inColNation)
i = i + 1
j = j + 1
Loop
If j = 1 Then '<- remove this if-statement and the following marked lines if single appearing UIs should be omitted entirely
.Cells(n, outColUI) = UI '<---
.Cells(n, outColNation1) = arr(1) '<---
n = n + 1 '<---
Else '<---
For k = 1 To j
For l = 1 To j
If arr(k) <> arr(l) Then
.Cells(n, outColUI) = UI
.Cells(n, outColNation1) = arr(k)
.Cells(n, outColNation2) = arr(l)
n = n + 1
End If
Next l
Next k
End If '<---
Loop
End With
End Sub
Edit: cleaned up the code a little bit
Something like the following shows how to iterate through 2 ranges of cells
Dim Rng1 as Range, Rng2 as Range
Dim SrcCell as Range, OthrCell as Range
Dim FullList as string
Rng1 = Range("A1:A12")
Rng2 = Range("B1:B12")
FullList = ""
For Each SrcCell in Rng1
For Each OthrCell in Rng2
FullList = IIF(FullList="","",FullList & vbCrLf) & SrcCell.Value & OthrCell.Value
Next OthrCell
Next srcCell
The FullList string now contains all the combinations but you may require something else. Only intended to give you a start
You need to add code yourself to filter out duplicates
You can do the following (see code below). As another commentee mentioned, when there is only one record of company vs country, it will not show in the output.
The solutions is based on creating a dictionary, each entry is a company and the value is a comma separated string of countries. After the dictionary is created, the dictionary is looped, and a list of countries is then iterated over a nested loop. If the index of the outer loop is the same as the inner index of the loop then the loop is skipped i.e. that would be a Country 1 vs Country 1 combination. Otherwise is added to the output list.
Columns A,B is input and columns D,E,F is output.
Option Explicit
Public Sub sCombine()
Dim r As Range, dest As Range
Dim d As New Dictionary
Dim key As Variant
Dim countries() As String
Dim i As Integer, j As Integer
On Error GoTo error_next
Set r = Sheet1.Range("A1")
Set dest = Sheet1.Range("D:F")
dest.ClearContents
Set dest = Sheet1.Range("D1")
While r.Value <> ""
If d.Exists(r.Value) Then
d(r.Value) = d(r.Value) & "," & r.Offset(0, 1)
Else
d.Add r.Value, r.Offset(0, 1).Value
End If
Set r = r.Offset(1, 0)
Wend
For Each key In d.Keys
countries = Split(d(key), ",")
For i = LBound(countries) To UBound(countries)
For j = LBound(countries) To UBound(countries)
If i <> j Then
dest.Value = key
dest.Offset(0, 1).Value = countries(i)
dest.Offset(0, 2).Value = countries(j)
Set dest = dest.Offset(1, 0)
End If
Next j
Next i
Next key
Exit Sub
error_next:
MsgBox Err.Description
End Sub

Creating an Array From Criteria

I have the following code, that is doing some if's, but with the values I am struggling to see how I create, and add the values to an array. At the moment, I am just adding the values to a listbox
List(lC, 0) = sh1.Cells(row, 23)
I tried creating an integer and, and then used something like
var = var & List(lC, 0) = sh1.Cells(row, 23)
But I am not sure if that's the correct way?
Private Sub CommandButton3_Click()
Dim sh1
Dim LR
Dim lC
Dim row
Me.lstUsedRooms.Clear
Set sh1 = ThisWorkbook.Worksheets(4) 'room order from sheets
With sh1
LR = .Range("A" & .Rows.Count).End(xlUp).row
End With
lC = 0
With Me.lstUsedRooms
.ColumnCount = 1 'there is 8 columns
.RowSource = ""
.ColumnWidths = 40
For row = 2 To LR
NewIVTime = Format("14:00", "h:mm:ss")
If Left(sh1.Cells(row, 6), 10) = "24/05/2019" Then ' Gets all interviews for the date specified
Dim LTime As Date
Dim LTime1 As Date
LTime = Format(sh1.Cells(row, 7), "h:mm:ss") 'Gets the times from all the rooms from the date stated above
LTime1 = CDate(LTime) + 3 / 24 ' Adds 3 hours to the time above
If LTime1 < NewIVTime Then ' Check which interviews display three hours after the new interview
.AddItem
.List(lC, 0) = sh1.Cells(row, 23)
lC = lC + 1
End If
End If
Next
If .ListCount = 0 Then
Me.lstUsedRooms.ColumnWidths = 100
Me.lstUsedRooms.AddItem "No Rooms"
End If
End With
End Sub
First see what you are going to be inputting, if you only need a 1 dimensional array then the best option is a collection:
Dim newCollection as New Collection
For each r in Range
newCollection.Add Value 'Add value here
Next r
If you are needing a multidimensional array then the array function is the best way:
Dim zArray() as variant
Redim zArray(x, y, ...) 'x and y are size of array
Or
Redim Preserve zArray(x, y, ...) 'If you loop through the Redim
For i = 1 to x
For j = 1 to y
zArray(x,y)
Next j
Next i

Resources