The below Code Counts the number of unique names is a specific column after inputting the data into an array. It works perfectly when running in the the immediate window. But when using as a UDF it throws #Value Error. I am taking all the data into an array and checking the array and getting a number out of it and returning it. I am not modifying any excel sheets or changing the worksheet's environment. Please help!!1
Public Function Operator_Count(Aircraft As String) As Integer
Dim Aircraft_Name As String
Dim Data_Array() As Variant
Dim Row_Count As Integer
Dim Col_Count As Integer
Dim Col_Alph As String
Dim Row_Counter As Integer
Dim Master_Series_Column As Integer
Dim Status_Column As Integer
Dim Operator_Column As Integer
Dim InnerLoop_Counter As Integer
Dim Operator_Array() As Variant
Dim Operator_Array_Transpose() As Variant
Dim Array_Counter As Integer
Aircraft_Name = Aircraft
Operator_Count = 0
'ThisWorkbook.Sheets("Aircraft Data").Activate
Row_Count = ThisWorkbook.Sheets("Aircraft Data").Range("A2", Range("A2").End(xlDown)).Rows.Count
Col_Count = ThisWorkbook.Sheets("Aircraft Data").Cells(1, Columns.Count).End(xlToLeft).Column
Col_Alph = ColumnLetter(Col_Count)
Data_Array = ThisWorkbook.Sheets("Aircraft Data").Range("A1:" & Col_Alph & Row_Count + 1).Value2
For Row_Counter = 1 To Col_Count
If Data_Array(1, Row_Counter) = "Master Series" Then
Master_Series_Column = Row_Counter
End If
Next
For Row_Counter = 1 To Col_Count
If Data_Array(1, Row_Counter) = "Status" Then
Status_Column = Row_Counter
End If
Next
For Row_Counter = 1 To Col_Count
If Data_Array(1, Row_Counter) = "Operator" Then
Operator_Column = Row_Counter
End If
Next
'Resizing the data array
ReDim Operator_Array(0, 0)
'Adding column to the data array
InnerLoop_Counter = 0
For Row_Counter = 1 To UBound(Data_Array)
If Data_Array(Row_Counter, Master_Series_Column) = Aircraft_Name And (Data_Array(Row_Counter, Status_Column) = "In Service" Or Data_Array(Row_Counter, Status_Column) = "On order") Then
Flag = 0
For Array_Counter = 0 To UBound(Operator_Array, 2)
If Operator_Array(0, Array_Counter) = Data_Array(Row_Counter, Operator_Column) Then
Flag = 1
Array_Counter = UBound(Operator_Array, 2)
End If
Next
If Flag <> 1 Then
ReDim Preserve Operator_Array(0, InnerLoop_Counter)
Operator_Array(0, InnerLoop_Counter) = Data_Array(Row_Counter, Operator_Column)
InnerLoop_Counter = InnerLoop_Counter + 1
End If
End If
Next
Operator_Count = UBound(Operator_Array, 2)
End Function
Function ColumnLetter(ColumnNumber As Integer) As String
Dim n As Integer
Dim c As Byte
Dim s As String
n = ColumnNumber
Do
c = ((n - 1) Mod 26)
s = Chr(c + 65) & s
n = (n - c) \ 26
Loop While n > 0
ColumnLetter = s
End Function
Related
I am using one existing VBA macro code to convert the xml data into table format and Vise versa from the excel sheet.
It was working fine on windows 7.
But in windows 10 I am getting the error saying that ""user-defined type not defined" on the line of code "Dim XmlDoc As MSXML2.DOMDocument"
Please help me How I can resolve this error ?
Private Function ParseRateClob(ByRef ClobRange As Range, ByRef StartRow As Long, ByRef ColumnMap As Object, ByVal ColumnLimit As Integer, ByRef Pk() As String) As Integer
Dim XmlDoc As MSXML2.DOMDocument
Dim ComplexList As MSXML2.IXMLDOMSelection
Dim ComplexNode As MSXML2.IXMLDOMNode
Dim DimensionsNode As MSXML2.IXMLDOMNode
Dim DimensionNode As MSXML2.IXMLDOMNode
Dim ComplexXPath As String
Dim ClobStr As String: ClobStr = ""
Dim Name As String
Dim Value As String
Dim Column As Integer
Dim MaxColumn As Integer
Dim i As Long
Dim j As Long
Dim c As Range
Dim Data() As Variant
MaxColumn = 1
For Each c In ClobRange
Value = c.Value
If InStr(Value, "'=") = 1 Then
Value = Mid(Value, 2, Len(Value) - 1)
End If
ClobStr = ClobStr & Value
Next
Set XmlDoc = New MSXML2.DOMDocument
If XmlDoc.LoadXML(ClobStr) Then
Set ComplexList = XmlDoc.SelectNodes(COMPLEX_XPATH)
'note that lists are zero based
For i = 0 To (ComplexList.Length - 1)
If i = 0 Then
ReDim Data(1, ColumnLimit)
Data(1, 1) = Pk(1)
Else
Call AddRow(Data)
End If
For j = 2 To 5
Data(i + 1, j) = Pk(j)
Next j
Set ComplexNode = ComplexList.Item(i)
For j = 0 To (ComplexNode.ChildNodes.Length - 2)
Name = ComplexNode.ChildNodes.Item(j).Attributes.Item(0).Text
Value = ComplexNode.ChildNodes.Item(j).Attributes.Item(1).Text
Column = GetColumn(Name, MaxColumn, ColumnMap, ColumnLimit)
Data(i + 1, Column) = Value
Next
Set DimensionsNode = ComplexNode.ChildNodes.Item(ComplexNode.ChildNodes.Length - 1)
For j = 0 To (DimensionsNode.ChildNodes.Length - 1)
Set DimensionNode = DimensionsNode.ChildNodes.Item(j)
Name = DimensionNode.ChildNodes.Item(0).Attributes.Item(1).Text
Value = DimensionNode.ChildNodes.Item(2).Attributes.Item(1).Text
Column = GetColumn(Name, MaxColumn, ColumnMap, ColumnLimit)
Data(i + 1, Column) = EscapeXL(Value)
Next
Next
Else
Err.Raise XmlDoc.parseError.ErrorCode, "", XmlDoc.parseError.reason
End If
Range(Cells(StartRow, 1), Cells(StartRow + i - 1, MaxColumn)) = Data
ActiveSheet.Hyperlinks.Add Anchor:=Cells(StartRow, 1), Address:="", SubAddress:=Replace(Data(1, 1), "$", "")
StartRow = StartRow + i
ParseRateClob = MaxColumn
End Function
I need your help to build a macro that can extract the dates (which are in text format) from a string and report them in a different column - let's say to column K, would you be able to assist?
Below the database in text
Contract
OESX BLT 100 Feb22 Mar22 4200 vs S 5 FESX Mar22 #4080
OESX P 100 Mar22 3050 vs 6 FESX Mar22 #4080
OESX CDIA 100 Feb22 4300 Mar22 4400 vs B 3 FESX Mar22 #4090
OESX CNV 100 Dec23 4100 vs 100 FESX Mar22 #4100
OESX PBUT Feb22 3900 - 4000 - 4100
The length of the column of the database is not fixed, it changes every time.
The final goal would be to put the dates at the beginning of the contract and not in the middle.
I thank you in advance :)
CODE:
Sub Macro8()
Dim sht As Worksheet
Dim fnd As Variant
Dim rplc As Variant
Dim row
Dim column
Dim value
fndList = Array("Dec22 ", "Dec23 ")
rplcList = Array("", "")
Set sht = Sheets("Data")
****For Each cell In Range("A2:A40")
If InStr(cell.Text, fndList) > 0 Then
cell.Offset(0, 1).value = fndList
End If
Next cell****
For x = LBound(fndList) To UBound(fndList)
sht.Cells.Replace What:=fndList(x), Replacement:=rplcList(x), _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
Next x
End Sub
Simple original answer:
Function RearrangeContract(ref As String)
Dim I As Integer
Dim N As Integer
Dim Res As String
Dim Con As String
Con = ref
For I = 1 To Len(ref) - 3
For N = 1 To 12
If Mid(ref, I, 3) = Format(DateSerial(2021, N, 15), "mmm") Then
Res = Res & Mid(ref, I, 5) & " "
Con = Replace(Con, Mid(ref, I, 6), "")
End If
Next N
Next I
RearrangeContract = Res & Con
End Function
Should spit out strings exactly as you requested.
[enter image description here][1]
Either use the function in your own code, or import the contract lines into excel and use =RearrangeContract() as a UDF
And here we have an absolute mess of code for such a small task, but I'm roughly 90% sure it will work perfectly.
FYI: I went the lazy route for the sorting, and borrowed a sorting sub from here: https://bettersolutions.com/vba/arrays/sorting-counting-sort.htm
Should rearrange, sort and filter duplicates
in the top function, you can change the date output format here:
"Res(i) = Format(Res(i), "mmmyy")"
Option Explicit
Option Base 0
Function RearrangeContractUnique(ref As String)
Dim i As Integer 'Character counter
Dim N As Integer 'Month counter
Dim Res() 'Result
Dim Con As String 'Contract - dates
Dim CNT As Integer 'Date found counter
Dim Temp
CNT = 0 'Counter to 0
Con = ref 'Store reference separately
For i = 1 To Len(ref) - 3 'Cycle through character in ref
For N = 1 To 12 'Test each month againt section of ref
If Mid(ref, i, 3) = Format(DateSerial(2021, N, 15), "mmm") Then
CNT = CNT + 1 'Increment counter
ReDim Preserve Res(1 To CNT) 'Resize array
'Debug.Print Mid(ref, i + 3, 2)
Res(CNT) = DateValue(DateSerial(20 & Mid(ref, i + 3, 2), N, 1))
Con = Replace(Con, Mid(ref, i, 6), "") 'Remove date found from ref
End If
Next N
Next i
'Debug.Print "PreSort"
'For i = 1 To CNT
'Debug.Print Res(i)
'Next i
Array_CountingSort Res
'Debug.Print "PostSort"
'For i = 1 To CNT
'Debug.Print Res(i)
'Next i
'Reformat for output
For i = 1 To CNT
Res(i) = Format(Res(i), "mmmyy")
Next i
'Yeah, just shovel more worksheetfunctions into it.
RearrangeContractUnique = Join(Application.WorksheetFunction.Transpose _
(WorksheetFunction.Unique(Application.WorksheetFunction. _
Transpose(Res())))) & " " & Con
End Function
Public Sub Array_CountingSort(ByRef vArrayName As Variant)
Dim vCounting() As Long
Dim lLower As Long
Dim lUpper As Long
Dim larraymin As Long
Dim larraymax As Long
Dim i As Long
Dim j As Long
Dim lnextpos As Long
larraymin = Helper_Minimum(vArrayName)
larraymax = Helper_Maximum(vArrayName)
lLower = LBound(vArrayName)
lUpper = UBound(vArrayName)
ReDim vCounting(larraymin To larraymax)
For i = lLower To lUpper
vCounting(vArrayName(i)) = vCounting(vArrayName(i)) + 1
Next i
lnextpos = lLower
For i = larraymin To larraymax
For j = 1 To vCounting(i)
vArrayName(lnextpos) = i
lnextpos = lnextpos + 1
Next j
Next i
End Sub
Public Function Helper_Maximum(ByVal vArrayName As Variant) As Long
Dim lmaxvalue As Long
Dim lrowlower As Long
Dim lrowupper As Long
Dim i As Long
lrowlower = LBound(vArrayName)
lrowupper = UBound(vArrayName)
lmaxvalue = vArrayName(lrowlower)
For i = lrowlower To lrowupper
If (vArrayName(i) > lmaxvalue) Then
lmaxvalue = vArrayName(i)
End If
Next i
Helper_Maximum = lmaxvalue
End Function
Public Function Helper_Minimum(ByVal vArrayName As Variant) As Long
Dim lminvalue As Long
Dim lrowlower As Long
Dim lrowupper As Long
Dim i As Long
lrowlower = LBound(vArrayName)
lrowupper = UBound(vArrayName)
lminvalue = vArrayName(lrowlower)
For i = lrowlower To lrowupper
If (vArrayName(i) < lminvalue) Then
lminvalue = vArrayName(i)
End If
Next i
Helper_Minimum = lminvalue
End Function
I have the follow code to fill cells in excel one by one and it works the way I want it to but it gives me this error when it runs through the array. How do I fix this error? Thanks
The error is "Subscript out of range. Error: 9"
Dim item As Variant
Dim splitString() As String
Dim finalSplit() As String
i = 1
For Each item In splitString
finalSplit = Split(splitString(s), ",")
Cells(i, 1) = finalSplit(0)
Cells(i, 2) = finalSplit(1)
Cells(i, 3) = finalSplit(2)
Cells(i, 4) = finalSplit(3)
i = i + 1
s = s + 1
Next
I checked if finalSplit contains enough values like Thomas said and it worked.This is the new code below.
Dim item As Variant
Dim splitString() As String
Dim finalSplit() As String
i = 1
For Each item In splitString
finalSplit = Split(splitString(s), ",")
If UBound(finalSplit) > 1 Then
Cells(i, 1) = finalSplit(0)
Cells(i, 2) = finalSplit(1)
Cells(i, 3) = finalSplit(2)
Cells(i, 4) = finalSplit(3)
i = i + 1
s = s + 1
End If
Next
As other commenters have pointed out, why not add another control variable?
Dim item As Variant
Dim splitString() As String
Dim finalSplit() As String
Dim i As Integer, j As Integer, s As Integer
i = 1
For Each item In splitString
finalSplit = Split(splitString(s), ",")
For j = 0 To UBound(finalSplit)
Cells(i, j + 1) = finalSplit(j)
Next j
i = i + 1
s = s + 1
Next
Be aware that this can loop more than the 4 times you expect. A lazy way to solve this would be to add If j > 3 Then Exit For before Next j
I tested this with the following code (it works!), as I have no idea what splitString() or finalSplit() is in your case:
Sub test()
Dim finalSplit As Variant
Dim j As Integer
finalSplit = Split("1,2,3,4,5", ",")
For j = 0 To UBound(finalSplit)
Cells(1, j + 1) = finalSplit(j)
If j > 3 Then Exit For
Next j
End Sub
Looping Through Elements of Arrays
An array created by the Split function is always 0-based (even if Option Base 1). Similarly, not quite related, an array created by the Array function is dependent on Option Base unless you use its parent VBA e.g. arr = VBA.Array(1,2,3). Then it is always zero-based.
Looping through the elements of an array (1D array) is done in the following two ways:
For Each...Next
Dim Item As Variant
For Each Item In Arr
Debug.Print Item
Next Item
For...Next
Dim i As Long
For i = LBound(Arr) To Ubound(Arr)
Debug.Print Arr(i)
Next i
Since we have established that Split always produces a zero-based array, in the second example we could use 0 instead of LBound(Arr):
`For...Next`
Dim i As Long
For i = 0 To Ubound(Arr)
Debug.Print Arr(i)
Next i
Option Explicit
Sub DoubleSplit()
Const IniString As String = "A,B,C,D/E,F,G,H/I,J,K/L/M,N,O,P,Q,R"
Dim SplitString() As String: SplitString = Split(IniString, "/")
Dim ws As Worksheet: Set ws = ActiveSheet ' be more specific
ws.Cells.ClearContents ' remove previous data; clears the whole worksheet
Dim FinalSplit() As String
Dim Item As Variant ' SplitString Control Variable
Dim r As Long ' Worksheet Row Counter
Dim f As Long ' FinalSplit Element Counter
' For Each...Next
For Each Item In SplitString
r = r + 1
FinalSplit = Split(Item, ",")
Debug.Print Join(FinalSplit, ",")
For f = 0 To UBound(FinalSplit)
ws.Cells(r, f + 1).Value = FinalSplit(f)
Next f
Next Item
r = r + 1 ' add an empty row
Dim s As Long ' SplitString Element Counter
' For...Next
For s = 0 To UBound(SplitString)
r = r + 1
FinalSplit = Split(SplitString(s), ",")
Debug.Print Join(FinalSplit, ",")
For f = 0 To UBound(FinalSplit)
ws.Cells(r, f + 1).Value = FinalSplit(f)
Next f
Next s
' Results
' A,B,C,D
' E,F,G,H
' I,J,K
' L
' M,N,O,P,Q,R
'
' A,B,C,D
' E,F,G,H
' I,J,K
' L
' M,N,O,P,Q,R
End Sub
Every part of this Code is executed but the part inside of the for loop on the top
I tried to rewrite this part of the code because one time it helped in vba but just this part would want to run
Do While Not IsEmpty(Sheets("Overview").Cells(ovrow, ovcol))
For row = 2 To length
If Sheets(wsname).Cells(row, column) = Sheets("Overview").Cells(ovrow, ovcol) Then
counter = counter + 1
End If
Next row
Sheets("Overview").Cells(ovrow, ovcol).Offset(0, 1).value = counter
counter = 0
If Sheets("Overview").Cells(ovrow, ovcol).Offset(1, 0).value = "" Then
ovrow = 2
ovcol = ovcol + 2
column = column + 1
Else
ovrow = ovrow + 1
End If
Cells(ovrow, ovcol).Select
Loop
It should just count to the variable counter higher but nothing happens. I put some messageboxes inside my code so i can see where the code is in the excel cells but the counter variable stays at 0
This is the full code
Private Sub RefreshBtn_Click()
Dim source As String
Dim sourcerow As Integer
Dim sourcecolumn As Integer
Dim target As String
Dim targetrow As Integer
Dim targetcolumn As Integer
Dim i As Integer
sourcerow = 2
sourcecolumn = 1
source = Sheets("Devices").Cells(sourcerow, sourcecolumn).value
targetrow = 2
targetcolumn = 3
For i = 1 To 6
Do While Not IsEmpty(Cells(targetrow, targetcolumn))
Cells(targetrow, targetcolumn).value = ""
targetrow = targetrow + 1
Loop
targetrow = 2
targetcolumn = targetcolumn + 2
Next i
targetrow = 2
targetcolumn = 3
For i = 1 To 6
Do While Not IsEmpty(Sheets("Devices").Cells(sourcerow, sourcecolumn))
source = Sheets("Devices").Cells(sourcerow, sourcecolumn).value
Sheets("Overview").Cells(targetrow, targetcolumn).value = source
sourcerow = sourcerow + 1
targetrow = targetrow + 1
Loop
sourcecolumn = sourcecolumn + 1
sourcerow = 2
targetrow = 2
targetcolumn = targetcolumn + 2
Next i
Dim length As Integer
Dim row As Integer
Dim column As Integer
Dim yearnow As String
Dim monthnow As String
Dim daynow As String
Dim wsname As String
Dim readdate As String
Dim ws As Worksheet
daynow = Day(Now())
If daynow > 20 Then
monthnow = month(Now()) + 1
If monthnow = "Januar" Then
yearnow = Year(Now()) + 1
End If
Else
monthnow = month(Now())
yearnow = Year(Now())
End If
wsname = yearnow + MonthName(monthnow)
For Each ws In ActiveWorkbook.Sheets
If ws.Name = wsname Then
exist = True
End If
Next ws
Sheets("Overview").Cells(2, 2).value = wsname
row = 2
column = 4
length = 0
If exist = True Then
Do While Not IsEmpty(Sheets(wsname).Cells(row, column))
row = row + 1
length = length + 1
Loop
Else
MsgBox "Für den aktuellen Monat sind keine Offenen Bestellung vorhanden"
End If
Dim counter As Integer
counter = 0
Dim ovrow As Integer
Dim ovcol As Integer
ovrow = 2
ovcol = 3
Do While Not IsEmpty(Sheets("Overview").Cells(ovrow, ovcol))
For row = 2 To length
If Sheets("Overview").Cells(ovrow, ovcol).value = Sheets(wsname).Cells(row, column).value Then
counter = counter + 1
MsgBox "hallo"
End If
Next row
Sheets("Overview").Cells(ovrow, ovcol).Offset(0, 1).value = counter
counter = 0
If Sheets("Overview").Cells(ovrow, ovcol).Offset(1, 0).value = "" Then
ovrow = 2
ovcol = ovcol + 2
column = column + 1
Else
ovrow = ovrow + 1
End If
Cells(ovrow, ovcol).Select
Loop
End Sub
HI I have copied some code. It works fine as long there are more than two rows in each column. If there is only only one row it returns the value " "
'and not the first and only value in that column. Have can I get it to work?
Sub ListCombinations()
Dim col As New Collection
Dim c As Range, sht As Worksheet, res
Dim i As Long, arr, numCols As Long
Dim numCol As Integer
Dim Col_Cnt As Integer
Dim Rows_Cnt As Integer
Set sht = Worksheets("Sheet5")
Col_Cnt = sht.UsedRange.Columns.Count 'add
Rows_Cnt = sht.UsedRange.Rows.Count ' add
For Each c In sht.Range("A1:B1").Cells
col.add Application.Transpose(sht.Range(c, c.End(xlDown)))
numCols = numCols + 1
MsgBox "numCols = " & numCols
Next c
res = Combine(col, "~~")
For i = 0 To UBound(res)
arr = Split(res(i), "~~")
sht.Range("H1").Offset(i, 0).Resize(1, numCols) = arr
Next i
End Sub
'create combinations from a collection of string arrays
Function Combine(col As Collection, SEP As String) As String()
Dim rv() As String
Dim pos() As Long, lengths() As Long, lbs() As Long, ubs() As Long
Dim t As Long, i As Long, n As Long, ub As Long
Dim numIn As Long, s As String, r As Long
numIn = col.Count
MsgBox numIn
ReDim pos(1 To numIn)
ReDim lbs(1 To numIn)
ReDim ubs(1 To numIn)
ReDim lengths(1 To numIn)
t = 0
For i = 1 To numIn 'calculate # of combinations, and cache bounds/lengths
lbs(i) = LBound(col(i))
ubs(i) = UBound(col(i))
lengths(i) = (ubs(i) - lbs(i)) + 1
pos(i) = lbs(i)
t = IIf(t = 0, lengths(i), t * lengths(i))
Next i
ReDim rv(0 To t - 1) 'resize destination array
For n = 0 To (t - 1)
s = ""
For i = 1 To numIn
s = s & IIf(Len(s) > 0, SEP, "") & col(i)(pos(i)) 'build the string
Next i
rv(n) = s
For i = numIn To 1 Step -1
If pos(i) <> ubs(i) Then 'Not done all of this array yet...
pos(i) = pos(i) + 1 'Increment array index
For r = i + 1 To numIn 'Reset all the indexes
pos(r) = lbs(r) ' of the later arrays
Next r
Exit For
End If
Next i
Next n
Combine = rv
End Function