Why is multiple Application.VLookup into array dreadfully slow? - excel

I have an external workbook from which I need to get data into my main workbook.
In the past i did this using A LOT of vlookups - and as a result the calculation was extremely slow. In order to speed things up, I have tried to convert the data from the external workbook into an array(arr2), and then doing the lookups into this. The result is that it's even more slow now..
The lookup value is composed of the values from two cells. I roughly have 1000 rows which, the way i do it, needs to be looped through in 44 columns. While it is actually working on a limited amount of rows, after one hour it is still processing when listing all 1000 rows.
What can be done to speed things up?
Dim arr1() As Variant, arr2() As Variant, arr3() As Variant
Dim sup1 As Long, sup2 As Long, sup3 As Long, sup4 As Long, sup5 As Long, sup6 As Long, sup7 As Long,
sup8 As Long, sup9 As Long, sup10 As Long, sup11 As Long, sup12 As Long, sup13 As Long, sup14 As
Long, sup15 As Long
Dim i As Long, WS1 As Worksheet
Dim Book1 As Workbook, book2 As Workbook
Dim book2Name As String
book2Name = "SupportTables.xlsx"
Dim book2NamePath As String
book2NamePath = ThisWorkbook.Path & "\" & book2Name
Dim lastrow As Long
lastrow = Sheets("sheet1").Range("T" & Rows.Count).End(xlUp).Row
Set Book1 = ThisWorkbook
If IsOpen(book2Name) = False Then Workbooks.Open (book2NamePath)
Set book2 = Workbooks(book2Name)
Set WS1 = book2.Worksheets("pricediscinfo")
sup1 = Range("AN12")
sup2 = Range("AQ12")
...
sup15 = Range("CD12")
arr1 = Range("T15:T" & lastrow)
ReDim arr3(1 To UBound(arr1), 1 To 44)
arr2 = WS1.Range("a1").CurrentRegion.Value
For i = 1 To UBound(arr1)
arr3(i, 1) = Application.VLookup(arr1(i, 1) & sup1, arr2, 12, False)
arr3(i, 2) = Application.VLookup(arr1(i, 1) & sup1, arr2, 9, False)
...
arr3(i, 43) = Application.VLookup(arr1(i, 1) & sup15, arr2, 12, False)
arr3(i, 44) = Application.VLookup(arr1(i, 1) & sup15, arr2, 9, False)
Next i
Range("AN15:CE" & lastrow).Value = arr3
Any input appriciated!

Dictionaries are just a collection of key, value pairs like an 1 dimension array but with a string allowed as the key rather than just numbers. In this case because you want to look up 2 columns, the value that a key refers to I chose to be a 2 element array. For more complex cases you might just store the row number as the dictionary value and use it to get the value of any column on the lookup sheet (or array). See Dictionary Object
Update : (ws2.Cells(1, "I") corrected to (ws2.Cells(i, "I")
Option Explicit
Sub FasterLookUp()
Const WB2_NAME = "SupportTables.xlsx"
Const WS2_NAME = "pricediscinfo"
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim iLastrow As Long, i As Long
Dim arr1, arr2, arr3, sPath As String, s As String
Dim isOpen As Boolean, t0 As Single
Dim dict As Object, k
Set dict = CreateObject("Scripting.Dictionary")
Set wb1 = ThisWorkbook
Set ws1 = wb1.Sheets("Sheet1")
sPath = wb1.Path & "\"
' configuration
Dim sup(15) As String, supCol
supCol = Array("AN", "AQ", "AR", "AS", "AT", _
"AU", "AV", "AW", "AX", "AY", _
"AZ", "BA", "BB", "BC", "CD")
For i = 1 To 15
sup(i) = ws1.Cells(12, supCol(i - 1))
s = s & "sup(" & i & ") = " & sup(i) & vbCr
Next
MsgBox s ' for checking code
' open workbook if not already open
isOpen = False
For Each wb2 In Application.Workbooks
If wb2.Name = WB2_NAME Then
isOpen = True
Exit For
End If
Next
If isOpen = False Then
Set wb2 = Workbooks.Open(sPath & "\" & WB2_NAME, True, True) ' update links, read only
End If
Set ws2 = wb2.Sheets(WS2_NAME)
iLastrow = ws2.Cells(Rows.Count, "A").End(xlUp).Row
' build dictionary as lookup table
t0 = Timer
For i = 1 To iLastrow
k = Trim(ws2.Cells(i, "A")) ' key
If Len(k) > 0 Then
If dict.exists(k) Then
MsgBox "Duplicate key " & k, vbCritical, "Row " & i
Exit Sub
Else
' col I and col L
dict.Add k, Array(ws2.Cells(i, "I"), ws2.Cells(i, "L")) ' lookups
End If
End If
Next
MsgBox dict.Count & " Items scanned into dictionary from " & ws2.Name, _
vbInformation, "Took " & Int(Timer - t0) & " seconds"
' update this workbook
t0 = Timer
iLastrow = ws1.Cells(Rows.Count, "T").End(xlUp).Row
arr1 = ws1.Range("T15:T" & iLastrow)
ReDim arr3(UBound(arr1), 1 To 44)
For i = 1 To UBound(arr1)
s = arr1(i, 1)
k = s & sup(1)
If dict.exists(k) Then
arr3(i, 1) = dict(k)(1) ' col L
arr3(i, 2) = dict(k)(0) ' col I
Else
'Debug.Print "No match '" & k & "'"
End If
''
k = s & sup(15)
If dict.exists(k) Then
arr3(i, 1) = dict(k)(1) ' col L
arr3(i, 2) = dict(k)(0) ' col I
Else
'Debug.Print "No match '" & k & "'"
End If
Next i
If isOpen = False Then wb2.Close False ' close if opened
ws1.Range("AN15:CE" & iLastrow).Value = arr3
MsgBox "Udate done", vbInformation, "Took " & Int(Timer - t0) & " seconds"
End Sub

Related

i want to get the frequency of a data in a column using vba

i tried using dictionary but it only counts the repetition but i want to know the exact frequency of all datas in a column
what ive used is
Sub countThings()
Dim ws As Worksheet
Dim lastrow As Long, x As Long
Dim items As Object
Application.ScreenUpdating = False
Set ws = ActiveSheet
lastrow = ws.Range("B" & Rows.count).End(xlUp).Row
Set items = CreateObject("Scripting.Dictionary")
For x = 2 To lastrow
If Not items.exists(ws.Range("B" & x).Value) Then
items.Add ws.Range("B" & x).Value, 1
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
Else
items(ws.Range("B" & x).Value) = items(ws.Range("B" & x).Value) + 1
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
End If
Next x
items.RemoveAll
End Sub
and this gives me
[1: https://i.stack.imgur.com/Mhp5g.png][1]
but what i need is
[4: https://i.stack.imgur.com/UYOFu.png][4]
I think this is what you were after. Please try it.
Sub CountThings()
Dim Ws As Worksheet
Dim Items As Object ' Scripting.Dictionary
Dim Arr As Variant ' values in column B
Dim R As Long ' loop couner: Rows
Dim Key As Variant ' loop counter: dictionary keys
Set Items = CreateObject("Scripting.Dictionary")
Set Ws = ActiveSheet ' better: define tab by name
With Ws
' reading from the sheet is slow
' therefore read all items at once
Arr = .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp)).Value
' this is a 1-based 2-D array, like Arr([Rows], [Column])
' where column is always 1 because there's only 1 column
End With
For R = 1 To UBound(Arr)
If Items.Exists(Trim(Arr(R, 1))) Then
Items(Trim(Arr(R, 1))) = Items(Trim(Arr(R, 1))) + 1
Else
Items.Add Trim(Arr(R, 1)), 1
End If
Next R
ReDim Arr(1 To Items.Count, 1 To 2)
R = 0
For Each Key In Items.keys
R = R + 1
Arr(R, 1) = Key
Arr(R, 2) = Items(Key)
Next Key
' specify the top left cell of the target range
Ws.Cells(2, "C").Resize(UBound(Arr, 1), UBound(Arr, 2)).Value = Arr
Set Items = Nothing
End Sub
You need not Trim the Keys if you are sure that there can't be any stray leading or trailing blanks.
Your second picture doesn't need VBA. It can be produce by this formula, entered in C2 and copied down.
=COUNTIF($B$2:$B$13,$B2)
In fact, you can even do the job of my above code without VBA. Enter this formula in G2 of your sheet as an array formula (confirmed with CTL + SHIFT + ENTER if you don't have Excel 365), and the other one in H. Then copy both formulas down.
[G2] =IFERROR(INDEX($B$2:$B$13, MATCH(0, COUNTIF($G$1:G1, $B$2:$B$13), 0)), "")
[H2] =IF($G2<>"",COUNTIF($B$2:$B$13,$G2),"")
You need to assign values to column C after you have finished counting and therefore, need another loop:
Sub countThings()
Dim ws As Worksheet
Dim lastrow As Long, x As Long
Dim items As Object
Application.ScreenUpdating = False
Set ws = ActiveSheet
lastrow = ws.Range("B" & Rows.Count).End(xlUp).Row
Set items = CreateObject("Scripting.Dictionary")
For x = 2 To lastrow
If Not items.exists(ws.Range("B" & x).Value) Then
items.Add ws.Range("B" & x).Value, 1
Else
items(ws.Range("B" & x).Value) = items(ws.Range("B" & x).Value) + 1
End If
Next x
For x = 2 To lastrow
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
Next x
items.RemoveAll
Set items = Nothing
End Sub
A simpler way to achieve what you want is to let excel do the counting for you like this:
Sub countThings2()
Dim sDataAddress As String
With ActiveSheet
sDataAddress = "$B$2:$B$" & .Cells(Rows.Count, "B").End(xlUp).Row
With .Range(sDataAddress).Offset(0, 1)
.Formula2 = "=COUNTIF(" & sDataAddress & ",B2)"
.Value = .Value
End With
End With
End Sub
i use table and 2 functions. not simple way but works :)
Sub Fx()
Dim str_Tab() As String, str_Text As String, str_Result As String
Dim int_Counter As Integer, int_TabItemCounter As Integer, int_LastRow As Integer
Dim rng_WorkRange As Range
int_LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set rng_WorkRange = ActiveSheet.Range("A1:A" & int_LastRow)
For i = 1 To int_LastRow
str_Text = ActiveSheet.Range("A" & i)
If i > 1 Then
str_Result = IsInArray(str_Text, str_Tab)
If str_Result = -1 Then
int_TabItemCounter = UBound(str_Tab) - LBound(str_Tab)
ReDim str_Tab(int_TabItemCounter)
str_Tab(int_TabItemCounter) = str_Text
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
Else
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
End If ' If str_Result = -1
Else ' If i > 1
ReDim str_Tab(i)
str_Tab(i) = str_Text
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
End If ' If i > 1
Next i
End Sub
function to check is text in table
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
function to count item in range
Function CountThisItem(CountingRange As Range, a As String) As Integer
Dim rng_FindRange As Range
Dim LA As String
Set rng_FindRange = CountingRange.Find(a, lookat:=xlWhole)
If Not rng_FindRange Is Nothing Then
LA = rng_FindRange.Address
CountThisItem = 1
Do
Set rng_FindRange = CountingRange.Find(a, lookat:=xlWhole, after:=rng_FindRange)
If Not rng_FindRange Is Nothing And rng_FindRange.Address <> LA Then CountThisItem = CountThisItem + 1
Loop While rng_FindRange.Address <> LA
Else
CountThisItem = 0
End If
End Function

Save Array as Tab Delimited Text file in VBA

Sub ExportDataTSV()
Dim BCS As Worksheet
Dim Ctrl As Worksheet
Dim ws As Worksheet
Dim FName As String
Dim insertValues As String
Application.ScreenUpdating = False
Set BCS = ThisWorkbook.Sheets(Sheet2.Name)
Set Ctrl = ThisWorkbook.Sheets(Sheet1.Name)
#If Mac Then
NameFolder = "documents folder"
If Int(Val(Application.Version)) > 14 Then
'You run Mac Excel 2016
folder = _
MacScript("return POSIX path of (path to " & NameFolder & ") as string")
'Replace line needed for the special folders Home and documents
folder = _
Replace(SpecialFolder, "/Library/Containers/com.microsoft.Excel/Data", "")
Else
'You run Mac Excel 2011
folder = MacScript("return (path to " & NameFolder & ") as string")
End If
FName = folder & "bcs_output.tsv"
#Else
folder = Environ$("userprofile")
Debug.Print folder
FName = folder & "Documents\bcs_output.tsv"
#End If
If Ctrl.Range("D9") = "" Or Ctrl.Range("D10") = "" Then
MsgBox "Please enter the Scenario Year and Scenario you wish to save and click again", vbOKOnly
Exit Sub
End If
Ctrl.Range("D9").Copy
BCS.Range("AS2").PasteSpecial Paste:=xlPasteValues
Ctrl.Range("D10").Copy
BCS.Range("AT2").PasteSpecial Paste:=xlPasteValues
With BCS
numrows = .Cells(.Rows.Count, 1).End(xlUp).Row
numcol = .Cells(2, Columns.Count).End(xlToLeft).Column
.Range("AS1").Value = "scenario_year"
.Range("AS2:AS" & numrows).FillDown
.Range("AT1").Value = "scenario"
.Range("AT2:AT" & numrows).FillDown
.Range("AU1").Value = "save_date"
.Range("AU2").Formula = "=NOW()"
.Range("AU2:AU" & numrows).FillDown
.Range("AU2:AU" & numrows).NumberFormat = "yyyy-mm-dd hh:mm"
For x = 2 To numrows
Set rng1 = .Range("A" & x & ":R" & x)
Set rng2 = .Range("AC" & x & ":AF" & x)
Set rng3 = .Range("AH" & x & ":AK" & x)
Set rng4 = .Range("AN" & x & ":AO" & x)
Set rng5 = .Range("AS" & x & ":AU" & x)
Set Data = Union(rng1, rng2, rng3, rng4, rng5)
insertValues = Join2D(ToArray(Data), Chr(9))
Debug.Print insertValues
Call ConvertText(FName, insertValues)
Next x
End With
With BCS
.Activate
.Range("A1").Select
End With
Ctrl.Activate
Application.ScreenUpdating = True
MsgBox "Cluster Data saved to your documents folder, please upload the file here: ", vbOKOnly
End Sub
Function ToArray(rng) As Variant()
Dim arr() As Variant, r As Long, nr As Long
Dim ar As Range, c As Range, cnum As Long, rnum As Long
Dim col As Range
nr = rng.Areas(1).Rows.Count
ReDim arr(1 To nr, 1 To rng.Cells.Count / nr)
cnum = 0
For Each ar In rng.Areas
For Each col In ar.Columns
cnum = cnum + 1
rnum = 1
For Each c In col.Cells
arr(rnum, cnum) = c.Value
rnum = rnum + 1
Next c
Next col
Next ar
ToArray = arr
End Function
Public Function Join2D(ByVal vArray As Variant, Optional ByVal sWordDelim As String = " ", Optional ByVal sLineDelim As String = vbNewLine) As String
Dim i As Long, j As Long
Dim aReturn() As String
Dim aLine() As String
ReDim aReturn(LBound(vArray, 1) To UBound(vArray, 1))
ReDim aLine(LBound(vArray, 2) To UBound(vArray, 2))
For i = LBound(vArray, 1) To UBound(vArray, 1)
For j = LBound(vArray, 2) To UBound(vArray, 2)
'Put the current line into a 1d array
aLine(j) = vArray(i, j)
Next j
'Join the current line into a 1d array
aReturn(i) = Join(aLine, sWordDelim)
Next i
Join2D = Join(aReturn, sLineDelim)
End Function
Function ConvertText(myfile As String, strTxt As String)
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
With objStream
'.Charset = "utf-8"
.Open
.WriteText strTxt
.SaveToFile myfile, 2
'.Close
End With
'Set objStream = Nothing
End Function
I attempted the above to write the non-contiguous ranges to a tab delimited file. I get a 3004 error - Unable to write file from that code. I am not sure why it can't write the file and since I can't even write the file I can't tell if it will write each row of data until there are no more. Can anyone assist with at least helping me get the file to write?
You need to separate folder and "Documents\bcs_output.tsv" with a backslash. In MacOS I believe the path separator is ":" (colon), not "\" (backslash).

Generate the number of "(x,y)" data in a cell with reference to a number

(eg: 1=(x1,y1), 3=(x1,y1,x2,y2,x3,y3)
How do i remove the unnecessary "(,)" as shown below and put the number of position of the x,y coordinates of the reliability fail with reference to the number under the header of reliability fails?
Eg: Reliability fail counts =2 in device WLR8~LW~VBD~MNW should give me the position of that fail counts at the same row as the device at columnX. Anyways please ignore the data under the V and W column in my pictures.
Current output based on my code
What i really want
Current issue
Current issue2
where it should be
Dim output As Variant
Dim outputrow As Integer
output = ""
outputrow = 0
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Sheets(1)
Dim ia As Long
Dim lastrow2 As Long
lastrow2 = ws1.Range("U2:U" & ws1.Rows.Count).Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
If ws1.Range("U1") = "Reliability Fail" Then
For ia = 2 To lastrow2
If ws1.Cells(ia, "U").Value = 0 Then
output = output & "(" & ws1.Cells(ia, "Y").Value & "," & ws1.Cells(ia, "Z").Value & "),"
ElseIf output = "(,)," Then 'if there are no x and y values in Y and Z column stop showing "(,),"
output = ""
End If
If ws1.Cells(ia, "U").Value > 0 Then
ws1.Cells(ia, "U").Offset(0, 3).Value = Left(output, Len(output) - 1) 'extract the x and y values obtain in (x,y) format
'if there is "value" under reliability fails(column U), put the x y position at the same row as the "value" at column X
End If
Next
End If
I suggest using an inner loop so that extra brackets don't get added in the first place
Option Explicit
Sub test()
Dim output As Variant
Dim outputrow As Integer
Dim valueCount As Long, ib As Long
output = ""
outputrow = 0
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Sheets(1)
Dim ia As Long
Dim lastrow2 As Long
lastrow2 = ws1.Range("U2:U" & ws1.Rows.Count).Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
If ws1.Range("U1") = "Reliability Fail" Then
' Outer loop over all rows
For ia = 2 To lastrow2
valueCount = ws1.Cells(ia, "U").Value
output = ""
' Inner loop to process repeated rows
For ib = 1 To valueCount
output = output & "(" & ws1.Cells(ia + ib - 1, "Y").Value & "," & ws1.Cells(ia + ib - 1, "Z").Value & ")"
If ib < valueCount Then output = output & ","
Next ib
ws1.Cells(ia, "U").Offset(0, 3).Value = output
Next ia
End If
End Sub
EDIT
Here is the amended code in light of OP's later example:
Option Explicit
Sub test()
Dim output As Variant
Dim outputrow As Integer
Dim valueCount As Long, ib As Long, rowPointer As Long
output = ""
outputrow = 0
Dim ws1 As Worksheet
Set ws1 = ThisWorkbook.Sheets(1)
Dim ia As Long
Dim lastrow2 As Long
lastrow2 = ws1.Range("U2:U" & ws1.Rows.Count).Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
If ws1.Range("U1") = "Reliability Fail" Then
rowPointer = 2
' Outer loop over all rows
For ia = 2 To lastrow2
valueCount = ws1.Cells(ia, "U").Value
output = ""
' Inner loop to process repeated rows
For ib = 1 To valueCount
output = output & "(" & ws1.Cells(rowPointer, "Y").Value & "," & ws1.Cells(rowPointer, "Z").Value & ")"
If ib < valueCount Then output = output & ","
rowPointer = rowPointer + 1
Next ib
ws1.Cells(ia, "U").Offset(0, 3).Value = output
Next ia
End If
End Sub
First, strip out the extra blank pairs using this:
output = Replace(Range("X" & lRow), ",(,)", "")
You should then have it down to just the pairs you want.
Then split it based on ), and append a ) if it doesnt end in one. Here is an example you can use to incorporate it in your code:
Sub test()
Dim lRow As Long
Dim vSplit As Variant
Dim sResult As String
Dim output as String
For lRow = 2 To 3
If Len(Range("X" & lRow)) > 0 And Val(0 & Range("U" & lRow)) > 0 Then
output = Replace(Range("X" & lRow), ",(,)", "") ' this strips out the extra empty pairs
vSplit = Split(output, "),") ' this creates a string array, 1 item for each pair
sResult = vSplit(Val(Range("U" & lRow)) - 1) ' this gets the one you want based on column U ( -1 because the Split array is 0 based)
If Right$(sResult, 1) <> ")" Then sResult = sResult & ")" ' this adds a ")" if one is missing
Debug.Print sResult ' debug code
Range("X" & lRow) = sResult ' this adds the result to column X, replacing what was there
End If
Next
End Sub

Dynamic data structures in VBA

Currently I am trying to improve the performance of my VBA program, because it takes forever to perform some table operations.
During the programs runtime I am trying to store data in worksheets, but the write-operations take for ever and I would like to store this data dynamically instead of writing it into a worksheet to reduce the time it needs to run.
I was thinking about using arrays instead of the worksheets to store the data but I am not quite sure whether this will work because I do not know how many rows/columns my table exactly has.
Here my code, any help is appreciated!
Public row As Long
Public rowMax As Long
Public startRow As Integer
Public materialType As String
Public filter As String
Public col As Integer
Public colMax As Integer
Public isUsed As Boolean
Public a As Integer
Sub bestimmeObFelderGenutzt()
Debug.Print ("bestimmeObFelderGenutzt:begin" & " " & Now())
With Sheets("Sheet1")
filter = "I"
startRow = 2
rowMax = Sheets("Sheet1").Cells(.Rows.Count, "F").End(xlUp).row
colMax = Sheets("Sheet1").Cells(1, .Columns.Count).End(xlToLeft).Column
materialType = Sheets("Sheet1").Range(filter & startRow).Value
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "Nutzung"
For col = 1 To colMax
Sheets("Nutzung").Cells(1, col + 2).Value = Sheets("Sheet1").Cells(1, col).Value
Next col
For row = 2 To rowMax
Sheets("Nutzung").Range("A" & row).Value = Sheets("Sheet1").Range("A" & row).Value
Sheets("Nutzung").Range("B" & row).Value = Sheets("Sheet1").Range("I" & row).Value
For col = 1 To colMax
If IsEmpty(Sheets("Sheet1").Cells(row, col)) = False Then
isUsed = True
Sheets("Nutzung").Cells(row, col + 2).Value = 1
Else:
Sheets("Nutzung").Cells(row, col + 2).Value = 0
End If
Next col
Next row
End With
Debug.Print ("bestimmeObFelderGenutzt:end" & " " & Now())
End Sub
Sub findeUngenutzteSpalten(ByVal materialType As String, pos As Integer)
Debug.Print ("findeUngenutzteSpalten:begin" & " " & materialType & " " & Now())
With Sheets(materialType)
rowMax = Sheets(materialType).Cells(.Rows.Count, "F").End(xlUp).row
colMax = Sheets(materialType).Cells(1, .Columns.Count).End(xlToLeft).Column
Sheets("Auswertung").Cells(1, 1).Value = "Spaltenüberschrift:"
Dim a As Integer
For a = 1 To colMax
Sheets("Auswertung").Cells(a + 1, 1).Value = Sheets("Sheet1").Cells(1, a).Value
Next a
Sheets("Auswertung").Cells(1, pos + 1).Value = materialType
For col = 3 To colMax
For row = 2 To rowMax
If Sheets(materialType).Cells(row, col).Value = 1 Then
Sheets("Auswertung").Cells(col - 1, pos + 1).Value = "Ja"
GoTo WeiterCol
Else:
If row = rowMax Then
Sheets("Auswertung").Cells(col - 1, pos + 1).Value = "Nein"
Else:
GoTo WeiterRow
End If
End If
WeiterRow:
Next row
WeiterCol:
Next col
End With
Debug.Print ("findeUngenutzteSpalten:end" & " " & materialType & " " & Now())
End Sub
Sub kopiereZeilen(ByVal materialType As String)
Debug.Print ("kopiereZeilen:begin" & " " & materialType & " " & Now())
With Sheets("Nutzung")
rowMax = Sheets("Nutzung").Cells(.Rows.Count, "F").End(xlUp).row
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = materialType
Sheets("Nutzung").Cells(1, 1).EntireRow.Copy Sheets(materialType).Cells(1, 1)
Dim unusedRow As Long
For row = 2 To rowMax
unusedRow = Sheets(materialType).Cells.SpecialCells(xlCellTypeLastCell).Offset(1, 0).row
If Sheets("Nutzung").Cells(row, 2).Value = materialType Then
Sheets("Nutzung").Cells(row, 2).EntireRow.Copy Sheets(materialType).Cells(unusedRow, 1)
End If
Next row
End With
Debug.Print ("kopiereZeilen:end" & " " & materialType & " " & Now())
End Sub
Sub allesZusammen()
Debug.Print ("Hauptaufruf:begin" & " " & Now())
Dim types(10) As String
Dim element As Variant
Dim pos As Integer
bestimmeObFelderGenutzt
types(0) = "A"
types(1) = "B"
types(2) = "C"
types(3) = "D"
types(4) = "E"
types(5) = "F"
types(6) = "G"
types(7) = "H"
types(8) = "I"
types(9) = "J"
types(10) = "K"
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "Auswertung"
For Each element In types
kopiereZeilen (element)
pos = Application.Match(element, types, False)
findeUngenutzteSpalten element, pos
Next element
Debug.Print ("Hauptaufruf:end" & " " & Now())
End Sub
You can declare dynamic arrays. The general syntax is:
Dim Values() As Long
To use the array, you must first re-dimension it to the size you want. For example this declares a two-dimensional array of 3 x 5 values (zero based):
ReDim Values(2, 4)
If you want to size based on variables then use something like:
ReDim Values(myrowsize, mycolumnsize)
You can grow (or shrink) the array dynamically by using this syntax:
ReDim Preserve Values(2, mynewsize)
Note, that you can only re-dimension the last index of the array. So this is not allowed:
ReDim Preserve Values(mynewsize, 4)
But this is probably ok in your case, as you have a fixed number of columns.
It is perfectly ok to declare the dynamic array as a UDT. For example:
Type UDTInfo
valueA As Long
valueB As Long
End Type
Sub test()
Dim Values() As UDTInfo
ReDim Values(2, 4)
ReDim Preserve Values(2, 5)
End Sub
You can access the array in the normal way:
x = Values(1, 2)
You can copy one dynamic array to another directly, as long as the types and number of dimensions match (size doesn't matter):
Dim Values() As Integer
Dim Results() As Integer
Results = Values
And lastly, you can pass dynamic arrays to and from functions in the following way:
Function SomeFunc(ByRef Values() As Long) As Long()
Dim ReturnValues() As Long
ReturnValues = Values
SomeFunc = ReturnValues
End Function
Note, you only pass dynamic arrays ByRef but not ByVal.

My InputBox is not being evaluated...Code runs, but the code seems to jump right over it

my code seems to compile, and run correctly, but for some reason the Inputbox does not seems to be evaluated at all. The Inputbox is in the middle of the code, what I am trying to accomplish is to have a cells data evaluated against a MonthName, and if its a match then spit out a Inputbox to the User. The function it is evaluating is:
=IFERROR(VLOOKUP($A3,'G:\Financial\Facility Work Papers and Financials\1.
Operating Entities\Arbors\2. Financials\2018\5. May\[Arbors May 2018.xls]Trial
Balance'!$A$30:$H$100,8,FALSE),0)
Here is the code:
Sub Date1()
Dim r As Range
Dim s As String
Dim UserInput As String
Dim Curdate As Date
Dim newDate As String
Dim newDate1 As String
Dim newDate2 As String
Dim newDate3 As String
Dim LastCol As Integer
Dim LastRow As Integer
Dim j As Integer
Dim i As Integer
Dim k As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
With ActiveSheet
For k = 1 To 12
Curdate = CDate(k & " " & "01," & " " & "2018")
newDate1 = MonthName(Month(Curdate), False)
newDate2 = MonthName(Month(Curdate), True)
newDate3 = Month(Curdate)
newDate = newDate3 & "." & newDate2
Debug.Print newDate
Debug.Print newDate1
'Defining the loops parameteres
For Each r In ActiveSheet.Range("D3:D6").Cells.SpecialCells(xlCellTypeFormulas)
s = LCase(r.Formula)
If InStr(1, r, newDate1) > 0 Then
UserInput = Application.InputBox(prompt:=newDate1 & "is the current data, if this is the data you want", Title:="please click cancel, otherwise click OK", Default:=newDate1)
End If
Next r
Next k
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 1 To LastCol
For j = 1 To LastRow
With ActiveWorkbook.Sheets("Data")
.Range(.Cells(j, 1), .Cells(1, i)).Replace What:=oldDate3 & "." & " " & oldDate2, replacement:=newDate, LookAt:=xlPart, MatchCase:=False
.Range(.Cells(j, 1), .Cells(1, i)).Replace What:=oldDate1, replacement:=newDate1, LookAt:=xlPart, MatchCase:=False
End With
Next j
Next i
End With
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Debug.Print Curdate
Debug.Print newDate3 & "." & newDate2
Debug.Print newDate1
Debug.Print newDate
End Sub

Resources