I have a problem with a selfmade vba-code. The makro should solve the following problem: I use a "cockpitfile" It should load the elemts of two worksheets from two different Excel files into two Arrays. The Elements of these Arrays should be subtracted from each other. I want to get the difference from these two elements. As an example: ArrayElm1(1,1) - ArrayElm2(1,1) = ArrayElm3(1,1), ArrayElm1(1,2) - ArrayElm2(1,2) = ArrayElm3(1,2) etc.
On the first sight the code seems to work but when I check the results with my calculater the difference of the elements is wrong. Maybe there is a problem with the UBound because in my Ubound is only Array A?
Hope you can help me!
Sub Differenz1()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'Variabledefinition
Dim i As Long 'Index
Dim j As Long 'Index
Dim k As Long 'Index
Dim ArrayA As Variant 'Array
Dim ArrayB As Variant 'Array
Dim ArrayC(71, 25) As Variant 'Array
Dim myFile1 As String 'Workbookname
Dim myFile2 As String 'Workbookname
Dim wb1 As String 'Workbookname
Dim wb2 As String 'Workbookname
Dim WS_Count1 As Integer 'Count Worksheets
Dim WS_Count2 As Integer 'Count Worksheets
Dim arrays1 As String 'Dimension
Dim arrays2 As String 'Dimension
'Change the actual path
ChDrive "O:\"
ChDir "O:..."
myFile1 = Application.GetOpenFilename
Workbooks.Open Filename:=myFile1, ReadOnly:=True, IgnoreReadOnlyRecommended:=True
wb1 = ActiveWorkbook.Name
WS_Count1 = ActiveWorkbook.Worksheets.Count
myFile2 = Application.GetOpenFilename
Workbooks.Open Filename:=myFile2, ReadOnly:=True, IgnoreReadOnlyRecommended:=True
wb2 = ActiveWorkbook.Name
WS_Count2 = ActiveWorkbook.Worksheets.Count
For k = 1 To WS_Count1
ArrayA = Workbooks(wb1).Worksheets(k).Range("F5:Y75").Value
ArrayB = Workbooks(wb2).Worksheets(k).Range("F5:Y75").Value
For i = LBound(ArrayA, 1) To UBound(ArrayA, 1)
For j = LBound(ArrayA, 2) To UBound(ArrayA, 2)
If Not IsError(ArrayA(i, j)) And Not IsError(ArrayB(i, j)) Then ArrayC(i, j) = ArrayA(i, j) - ArrayB(i, j)
Next j
Next i
ThisWorkbook.Worksheets(k + 1).Range("F5:Y75").Value = ArrayC
Next k
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
You almost had it right, but the issues was that you didn't reset ArrayC
This code creates new sheets in ThisWorkbook for subtractions, and based on your previous question it checks for errors, and performs the subtractions only if both values are numbers
Option Explicit
Public Sub Differenz2()
Const USED_RNG = "F5:Y75" 'Main range
Dim i As Long, j As Long, k As Long, file1 As String, file2 As String, ws1Count As Long
Dim wb1 As Workbook, wb2 As Workbook, arr1 As Variant, arr2 As Variant, arr3 As Variant
'ChDrive "O:\": ChDir "O:..."
file1 = Application.GetOpenFilename: If file1 = "False" Then Exit Sub
file2 = Application.GetOpenFilename: If file2 = "False" Then Exit Sub
Application.ScreenUpdating = False
Set wb1 = Workbooks.Open(Filename:=file1, ReadOnly:=True)
Set wb2 = Workbooks.Open(Filename:=file2, ReadOnly:=True)
ws1Count = wb1.Worksheets.Count
If ws1Count = wb2.Worksheets.Count Then
MakeNewWS ws1Count 'Remove this line if ThisWorkbook is properly setup
For k = 1 To ws1Count
arr1 = wb1.Worksheets(k).Range(USED_RNG).Value
arr2 = wb2.Worksheets(k).Range(USED_RNG).Value
ReDim arr3(1 To 71, 1 To 20) 'reset array, based on USED_RNG ("F5:Y75")
For i = LBound(arr1, 1) To UBound(arr1, 1)
For j = LBound(arr1, 2) To UBound(arr1, 2)
If Not IsError(arr1(i, j)) And Not IsError(arr2(i, j)) Then
If IsNumeric(arr1(i, j)) And IsNumeric(arr2(i, j)) Then
arr3(i, j) = arr1(i, j) - arr2(i, j)
End If
End If
Next
Next
ThisWorkbook.Worksheets(k + 1).Range(USED_RNG) = arr3
Next
End If
wb1.Close False: wb2.Close False: ThisWorkbook.Worksheets(2).Activate
Application.ScreenUpdating = True
End Sub
Private Sub MakeNewWS(ByVal wsCount As Long)
Dim i As Long, ws As Worksheet
With ThisWorkbook.Worksheets
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If Left(ws.Name, 12) = "Subtraction " Then
If .Count = 1 Then .Add
ws.Delete
End If
Next
Application.DisplayAlerts = True
For i = 2 To wsCount + 1
.Add After:=ThisWorkbook.Worksheets(.Count)
ThisWorkbook.Worksheets(.Count).Name = "Subtraction " & i - 1
Next
End With
End Sub
You can ignore the MakeNewWS() sub if ThisWorkbook contains the proper number of sheets
Also, using arrays does improve performance (significantly)
Related
With following to this question Link
, I need to match the values found in wb1.coumns(1) with the other workbook wb2.coumns(1) with some particular conditions.
Wb2 will be filtered with the value Close at column 13 M.
My question: is to seek the Wb2 (the open workbook) Latest closing Date on column 11 K and then copy the respective values at columns (“B, and “Q:X”) (on the same row ),
Then paste these values in Wb1.columns (“S:AA”) respectively.
The below code designed to returns back with the respective values of only one column of wb2 (column “B”)
This is the Link for test workbooks.
Option Explicit
Option Compare Text
Sub Get_Respective_Values_Of_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range
Dim arr1() As Variant, arr2() As Variant
Dim dict As New Dictionary
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open(ThisWorkbook.path & "\Book_B.xlsb", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng1 = ws1.Range("A3:AA" & ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row) 'Main Range
Set rng2 = ws2.Range("A3:X" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row) 'Opened Workbook_Range
arr1 = rng1.Value2
arr2 = rng2.Value2
'place the unique last key in a dictionary:
Dim i As Long
For i = 1 To UBound(arr2)
If arr2(i, 13) = "Close" Then 'Column (Status)
If Not dict.Exists(arr2(i, 1)) Then
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11)) 'Place the _Date_ from K:K, too
Else
If CDate(arr2(i, 11)) > CDate(dict(arr2(i, 1))(1)) Then 'Change the item only in case of a more recent _Date_:
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11))
End If
End If
End If
Next i
'Place the necessary data in its place:
For i = 1 To UBound(arr1)
If dict.Exists(arr1(i, 1)) Then
arr1(i, 19) = dict(arr1(i, 1))(0) 'extract first item array element
Else
arr1(i, 19) = "NA"
End If
Next i
rng1.Value2 = arr1 'drop back the updated array content
ws1.Activate
' wb2.Close SaveChanges:=False
Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
Please, test the next updated code:
Sub Get_Respective_Values_Of_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range
Dim arr1() As Variant, arr2() As Variant
Dim dict As New Dictionary
'Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open(ThisWorkbook.path & "\Book_B.xlsb", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng1 = ws1.Range("A3:AA" & ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row) 'Main Range
Set rng2 = ws2.Range("A3:X" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row) 'Opened Workbook_Range
arr1 = rng1.Value2
arr2 = rng2.Value2
'place the unique last key in a dictionary:
Dim i As Long, arrAtt, j As Long, k As Long
ReDim arrAtt(7) 'the 1D array should contain maximum number of elements from "Q" to "X"
'meaning 8 columns. since arrAtt is 1D zero based, it may keep 8 elements
For i = 1 To UBound(arr2)
If arr2(i, 13) = "Close" Then 'Column (Status)
Erase arrAtt: ReDim arrAtt(7) 'erase the previous loaded array, if the case (to be loaded...)
If Not dict.Exists(arr2(i, 1)) Then
For j = 0 To UBound(arrAtt) 'iterate between the 8 array elements
If arr2(i, 17 + j) <> "" Then
arrAtt(k) = arr2(i, 17 + k): k = k + 1 'add the found URLs and increment k
Else
Exit For 'exit the iteration if no URL exists
End If
Next j
If k > 0 Then ReDim Preserve arrAtt(k - 1) 'keep only the loaded elements
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11), arrAtt) 'Place attachments array, too
k = 0 'reinitialize k variable
Else
If CDate(arr2(i, 11)) > CDate(dict(arr2(i, 1))(1)) Then 'Change the item only in case of a more recent Date
Erase arrAtt: ReDim arrAtt(7) 'erase the previous loaded array
For j = 0 To UBound(arrAtt)
If arr2(i, 17 + j) <> "" Then
arrAtt(k) = arr2(i, 17 + k): k = k + 1
Else
Exit For
End If
Next j
If k > 0 Then ReDim Preserve arrAtt(k - 1)
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11), arrAtt) 'Place attachments array, too
k = 0
End If
End If
End If
Next i
'Place the necessary data in its place:
For i = 1 To UBound(arr1)
If dict.Exists(arr1(i, 1)) Then
arr1(i, 19) = dict(arr1(i, 1))(0) 'extract first item array element
For j = 0 To UBound(dict(arr1(i, 1))(2)) 'extract existing URLs
If dict(arr1(i, 1))(2)(j) = "" Then Exit For 'exit the loop in case of empty strings
arr1(i, 20 + j) = dict(arr1(i, 1))(2)(j) 'place the URLs in their position
Next j
Else
arr1(i, 19) = "NA"
End If
Next i
rng1.Value2 = arr1 'drop back the updated array content
ws1.Activate
' wb2.Close SaveChanges:=False
Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
But, if you intend to adapt wb2 workbook in terms of clearing some URLs (for the latest closing Date) , the code should be adapted to preliminarily clear the range "S:AA" in wb1 till the end of the sheet. Otherwise, existing URLs may remain from the previous run
I have an array with fixed values. How can I find cells in Column B that contain all the 'String' values present in array?
Here is my code
With Worksheets("Data")
Dim kwrSets As Variant
.Activate
kwrSets = .Range("B2:B" & Application.WorksheetFunction.Max(2, .Range("A100000").End(xlUp).Row)).Value
For k = LBound(kwrSets) To UBound(kwrSets)
For i = LBound(arr) To UBound(arr)
Delete entire row if all values of arr not found in kwrSets
Next i
Next k
End With
Following is the updated code based on the answer below but it is giving error "Subscript out of range" in inStr line.
Sub Extractor()
Dim ws As Worksheet, wsd As Worksheet
Dim cell As Variant
Dim tmp As Variant
Dim blnFound As Boolean
Dim j As Long, i As Long
Dim kwrSets() As Variant
Dim arr() As String
Set ws = Worksheets("Sheet1")
With ws
.Activate
For Each cell In .Range("A1:A" & .Cells(.Rows.Count, "B").End(xlUp).Row)
If (cell.Offset(0, 2) = 1) Then
tmp = tmp & cell & "|"
End If
Next cell
If Len(tmp) > 0 Then tmp = Left(tmp, Len(tmp) - 1)
arr = Split(tmp, "|")
End With
Set wsd = Worksheets("Data")
With wsd
.Activate
kwrSets = .Range("B2:B" & Application.WorksheetFunction.Max(2, .Range("A100000").End(xlUp).Row)).Value
For k = LBound(kwrSets) To UBound(kwrSets)
blnFound = True
For i = LBound(arr) To UBound(arr)
If InStr(kwrSets(j, 1), arr(i)) = 0 Then
blnFound = False
Exit For
End If
Next i
Next k
End With
End Sub
Below is some VBA code that gets all of the data in column B into an array, then loops this array checking for the existence of each of the elements in the search array. If any of the search elements are not found, then it exits that loop. If all elements are found then it highlights the cell.
Sub sFindArray()
Dim ws As Worksheet
Dim aSearch() As Variant
Dim aData() As Variant
Dim lngLoop1 As Long
Dim lngLoop2 As Long
Dim lngFirstRow As Long
Dim lngLastRow As Long
Dim lngLBound As Long
Dim lngUBound As Long
Dim blnFound As Boolean
aSearch = Array("a", "b", "c")
lngLBound = LBound(aSearch)
lngUBound = UBound(aSearch)
Set ws = Worksheets("Sheet1")
lngLastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
aData() = ws.Range("B1:B" & lngLastRow)
lngFirstRow = LBound(aData, 1)
lngLastRow = UBound(aData, 1)
For lngLoop1 = lngFirstRow To lngLastRow
blnFound = True
For lngLoop2 = lngLBound To lngUBound
If InStr(aData(lngLoop1, 1), aSearch(lngLoop2)) = 0 Then
blnFound = False
Exit For
End If
Next lngLoop2
If blnFound = True Then
ws.Cells(lngLoop1, 2).Interior.Color = vbRed
End If
Next lngLoop1
End Sub
Regards,
I have an excel range with 67 columns and about 4500 rows. The objective is to replace values in a row with hardcoded values in the 67th column of each row and then mark the ones that have have been replaced.
So I need to check each cell in a row (of 66 columns) and see if they satisfy a certain condition, before replacing them with the said hardcoded value at the very end of the row. My run time is about 360 seconds on average, when I mark the replaced values as Bold text.
Sub searchreplace()
Dim StartTime As Double
Dim Seconds As Double
StartTime = Timer
Dim i As Long
Dim j As Long
Dim arr As Variant
Dim myRange As Range
Dim Rng As String
Dim wb As Workbook
Dim SheetName As String
Dim LessThanEqual As Long
Application.ScreenUpdating = False
Set wb = ThisWorkbook
SheetName = "INPUT_WIND"
Rng = "C3:BQ4466"
LessThanEqual = 1
Set myRange = wb.Worksheets(SheetName).Range(Rng)
arr = myRange.Value
'i = rows = Ubound(arr,1)
'j=columns = Ubound(arr,2)
'loop through rows and clmns
For i = 1 To UBound(arr)
For j = 1 To myRange.Columns.Count
If arr(i, j) <= LessThanEqual Then
arr(i, j) = arr(i, 67)
myRange.Cells(i, j).Select
With Selection
.Font.Bold = True
End With
ElseIf IsEmpty(arr(i, j)) = True Then
arr(i, j) = arr(i, 67)
End If
Next j
Next i
myRange.Value = arr
Seconds = Round(Timer - StartTime, 2)
MsgBox "Fertig" & Seconds & "Seconds", vbInformation
Application.ScreenUpdating = True
End Sub
Instead of this:
myRange.Cells(i, j).Select
With Selection
.Font.Bold = True
End With
do this:
myRange.Cells(i, j).Font.Bold = True
It will be up to >10x faster.
See here for more: How to avoid using Select in Excel VBA
Here's a full example detailing using Union to keep track of which cells qualify to receive the bold, then apply that formatting in one shot. It's taking about a second on my machine to complete.
Option Explicit
Sub searchreplace()
Const LessThanEqual As Long = 1
Dim StartTime As Double
Dim i As Long
Dim j As Long
Dim arr As Variant
Dim myRange As Range
Dim wb As Workbook
Dim UnionRange As Range
StartTime = Timer
Application.ScreenUpdating = False
Set wb = ThisWorkbook
Set myRange = wb.Worksheets("INPUT_WIND").Range("C3:BQ4466")
arr = myRange.Value
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
If IsEmpty(arr(i, j)) = False And arr(i, j) <= LessThanEqual Then
If UnionRange Is Nothing Then
Set UnionRange = myRange.Cells(i, j)
Else
Set UnionRange = Union(UnionRange, myRange.Cells(i, j))
End If
ElseIf IsEmpty(arr(i, j)) Then
arr(i, j) = arr(i, 67)
End If
Next
Next
UnionRange.Font.Bold = True
myRange.Value = arr
Debug.Print "This took: " & Round(Timer - StartTime, 2) & " Seconds"
Application.ScreenUpdating = True
End Sub
Found this code below that copies only "new" data from workbook1 to workbook2. It does what it suppose to but only limited to two columns A and B. My data span all the way to ZQ on every row. I tried to tweak the code for my purpose but its just beyond me. I appreciate any help.
Sub CompareArrays()
Dim arr1() As Variant, arr2() As Variant, arr3() As Variant
Dim i As Long, j As Long, k As Long, nextRow As Long
Dim wb1 As Workbook, wb2 As Workbook
Dim x As Boolean
Set wb1 = Workbooks("Workbook1.xlsm") 'Name of first workbook
Set wb2 = Workbooks("Workbook2.xlsx") 'Name of second workbook
arr1 = wb1.Sheets(1).Range("A2:B" & wb1.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row).Value
arr2 = wb2.Sheets(1).Range("A2:B" & wb2.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row).Value
For i = LBound(arr1) To UBound(arr1)
x = True
For j = LBound(arr2) To UBound(arr2)
If arr1(i, 1) = arr2(j, 1) Then
x = False
Exit For
End If
Next j
If x = True Then
k = k + 1
ReDim Preserve arr3(2, k)
arr3(1, k - 1) = arr1(i, 2)
arr3(0, k - 1) = arr1(i, 1)
End If
Next i
With wb2.Sheets(1)
nextRow = .Cells(Rows.Count, "A").End(xlUp).Row + 1
.Range(.Cells(nextRow, 1), .Cells(nextRow + k, 2)) = Application.Transpose(arr3)
End With
End Sub
Try following code:
Sub CompareArrays()
Dim arr1() As Variant, arr2() As Variant, arr3() As Variant
Dim i As Long, j As Long, k As Long, nextRow As Long
Dim wb1 As Workbook, wb2 As Workbook
Dim x As Boolean
Set wb1 = Workbooks("Workbook1.xlsm") 'Name of first workbook
Set wb2 = Workbooks("Workbook2.xlsx") 'Name of second workbook
arr1 = wb1.Sheets(1).Range("A2:A" & wb1.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row).Value
arr2 = wb2.Sheets(1).Range("A2:A" & wb2.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row).Value
k = 1
For i = LBound(arr1) To UBound(arr1)
x = True
For j = LBound(arr2) To UBound(arr2)
If arr1(i, 1) = arr2(j, 1) Then
x = False
Exit For
End If
Next j
If x = True Then
k = k + 1
pos = Application.Match(arr1(i, 1), arr1, False) + 1 'get position in array
nextRow = wb2.Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row + 1
wb2.Sheets(1).Rows(nextRow).EntireRow.Value = wb1.Sheets(1).Rows(pos).EntireRow.Value
End If
Next i
End Sub
I am working on a project that involves finding a particular column in a spreadsheet, then storing only unique values in that column into an array and then printing that array on another sheet. My code is erroring out due to both a type mismatch and a with block not being set, but I can't seem to figure out why. Any help would be greatly appreciated.
Option Explicit
Sub Find_Distincts_Policies()
Dim aCell As Range, rng As Range
Dim varIn As Variant, varUnique As Variant, element As Variant
Dim isUnique As Boolean
Dim ws As Worksheet
Dim wkb As Workbook
Dim colName As Long
Dim i As Long, j As Long, k As Long
Dim iInCol As Long, iInRow As Long, iUnique As Long, nUnique As Long, LastRow As Long
Set wkb = ThisWorkbook
Set ws = wkb.Worksheets("Sheet2")
With ws
Set aCell = .Range("A1:ZZ4").Find(what:="Unique Number", LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False)
If Not aCell Is Nothing Then
colName = Split(.Cells(, aCell).Address, "$")(1)
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng = .Range(colName & "2:" & colName & LastRow)
varIn = rng.Value
ReDim varUnique(1 To UBound(varIn, 1) * UBound(varIn, 2))
nUnique = 0
For iInRow = LBound(varIn, 1) To UBound(varIn, 1)
For iInCol = LBound(varIn, 2) To UBound(varIn, 2)
isUnique = True
For iUnique = 1 To nUnique
If varIn(iInRow, iInCol) = varUnique(iUnique) Then
isUnique = False
Exit For
End If
Next iUnique
If isUnique = True Then
nUnique = nUnique + 1
varUnique(nUnique) = varIn(iInRow, iInCol)
End If
Next iInCol
Next iInRow
ReDim Preserve varUnique(1 To nUnique)
MsgBox varUnique
Else: Exit Sub
End If
End With
With wkb
.Worksheets.Add.Name = "Unique values"
ActiveSheet.Range("A1") = varIn
End With
End Sub