how can i see the all possibilities using parameters - excel

I have 3 workers.
I need to make assembly line balancing.
There are 10 operations of model.
You can see the time of operations for all workers in the chart below. They have different abilities.
So I need to share all operations between 3 workers.
so what I need:
Worker and operations of model is changeable.
20 worker-25 operations
18 worker-40 operations
19 worker-75 operations
...
So I need to define parameters for all i. Maybe need to use a function?
Sub rapor_calistir()
Range("q1") = Now()
Sheets("Rapor").Range("A2:Z1048576").ClearContents
a = 2: worker1 = 0: worker2 = 0: worker3 = 0
For i1 = 1 To 3
For i2 = 1 To 3
For i3 = 1 To 3
For i4 = 1 To 3
For i5 = 1 To 3
For i6 = 1 To 3
For i7 = 1 To 3
For i8 = 1 To 3
For i9 = 1 To 3
Sheets("Rapor").Cells(a, 1) = a - 1
Sheets("Rapor").Cells(a, 2) = i1
Sheets("Rapor").Cells(a, 3) = i2
Sheets("Rapor").Cells(a, 4) = i3
Sheets("Rapor").Cells(a, 5) = i4
Sheets("Rapor").Cells(a, 6) = i5
Sheets("Rapor").Cells(a, 7) = i6
Sheets("Rapor").Cells(a, 8) = i7
Sheets("Rapor").Cells(a, 9) = i8
Sheets("Rapor").Cells(a, 10) = i9
Sheets("Rapor").Cells(a, 11) = i10
For i = 1 To 10
ara_toplam = ara_toplam + WorksheetFunction.VLookup(i, Sheets("Data").Columns("A:D"), Sheets("Rapor").Cells(a, i + 1) + 1, False)
If Sheets("Rapor").Cells(a, i + 1) = 1 Then
worker1 = worker1 + WorksheetFunction.VLookup(i, Sheets("Data").Columns("A:D"), Sheets("Rapor").Cells(a, i + 1) + 1, False)
ElseIf Sheets("Rapor").Cells(a, i + 1) = 2 Then
worker2 = worker2 + WorksheetFunction.VLookup(i, Sheets("Data").Columns("A:D"), Sheets("Rapor").Cells(a, i + 1) + 1, False)
ElseIf Sheets("Rapor").Cells(a, i + 1) = 3 Then
worker3 = worker3 + WorksheetFunction.VLookup(i, Sheets("Data").Columns("A:D"), Sheets("Rapor").Cells(a, i + 1) + 1, False)
End If
Next i
Sheets("Rapor").Cells(a, 12) = ara_toplam
Sheets("Rapor").Cells(a, 13) = worker1
Sheets("Rapor").Cells(a, 14) = worker2
Sheets("Rapor").Cells(a, 15) = worker3
ara_toplam = 0: worker1 = 0: worker2 = 0: worker3 = 0
a = a + 1
Next i10
Next i9
Next i8
Next i7
Next i6
Next i5
Next i4
Next i3
Next i2
Next i1
End Sub

This sounds like a combination problem (order doesn't matter).
Option Explicit
Sub main()
Call for_each_in_others(rDATA:=Worksheets("Sheet1").Range("A2"), bHDR:=True)
End Sub
Sub for_each_in_others(rDATA As Range, Optional bHDR As Boolean = False)
Dim v As Long, w As Long
Dim iINCROWS As Long, iMAXROWS As Long, sErrorRng As String
Dim vVALs As Variant, vTMPs As Variant, vCOLs As Variant
On Error GoTo bm_Safe_Exit
appTGGL bTGGL:=False
With rDATA.Parent
With rDATA(1).CurrentRegion
'Debug.Print rDATA(1).Row - .Cells(1).Row
With .Resize(.Rows.Count - (rDATA(1).Row - .Cells(1).Row), .Columns.Count).Offset(2, 0)
sErrorRng = .Address(0, 0)
vTMPs = .Value2
ReDim vCOLs(LBound(vTMPs, 2) To UBound(vTMPs, 2))
iMAXROWS = 1
'On Error GoTo bm_Output_Exceeded
For w = LBound(vTMPs, 2) To UBound(vTMPs, 2)
vCOLs(w) = Application.CountA(.Columns(w))
iMAXROWS = iMAXROWS * vCOLs(w)
Next w
'control excessive or no rows of output
If iMAXROWS > Rows.Count Then
GoTo bm_Output_Exceeded
ElseIf .Columns.Count = 1 Or iMAXROWS = 0 Then
GoTo bm_Nothing_To_Do
End If
On Error GoTo bm_Safe_Exit
ReDim vVALs(LBound(vTMPs, 1) To iMAXROWS, LBound(vTMPs, 2) To UBound(vTMPs, 2))
iINCROWS = 1
For w = LBound(vVALs, 2) To UBound(vVALs, 2)
iINCROWS = iINCROWS * vCOLs(w)
For v = LBound(vVALs, 1) To UBound(vVALs, 1)
vVALs(v, w) = vTMPs((Int(iINCROWS * ((v - 1) / UBound(vVALs, 1))) Mod vCOLs(w)) + 1, w)
Next v
Next w
End With
End With
.Cells(2, UBound(vVALs, 2) + 2).Resize(1, UBound(vVALs, 2) + 2).EntireColumn.Delete
If bHDR Then
rDATA.Cells(1, 1).Offset(-1, 0).Resize(1, UBound(vVALs, 2)).Copy _
Destination:=rDATA.Cells(1, UBound(vVALs, 2) + 2).Offset(-1, 0)
End If
rDATA.Cells(1, UBound(vVALs, 2) + 2).Resize(UBound(vVALs, 1), UBound(vVALs, 2)) = vVALs
End With
GoTo bm_Safe_Exit
bm_Nothing_To_Do:
MsgBox "There is not enough data in " & sErrorRng & " to perform expansion." & Chr(10) & _
"This could be due to a single column of values or one or more blank column(s) of values." & _
Chr(10) & Chr(10) & "There is nothing to expand.", vbInformation, _
"Single or No Column of Raw Data"
GoTo bm_Safe_Exit
bm_Output_Exceeded:
MsgBox "The number of expanded values created from " & sErrorRng & _
" (" & Format(iMAXROWS, "\> #, ##0") & " rows × " & UBound(vTMPs, 2) & _
" columns) exceeds the rows available (" & Format(Rows.Count, "#, ##0") & ") on this worksheet.", vbCritical, _
"Too Many Entries"
bm_Safe_Exit:
appTGGL
End Sub
Sub appTGGL(Optional bTGGL As Boolean = True)
Application.EnableEvents = bTGGL
Application.ScreenUpdating = bTGGL
End Sub
Before:
After:
Expanding column cells for each column cell

Related

Data cleaning and identification of incomplete orders

Sub FormatAndIncompleteOrders()
Dim a, Q&, i&, b(1 To 2), R, j%
Application.ScreenUpdating = False
Rem -----------------------------------\
a = Range("'Original Data'!A3").CurrentRegion: Q = UBound(a)
ReDim R(1 To Q, 1 To 4): b(1) = R: b(2) = R
ReDim R(1 To 2) As Long
Rem -----------------------------------\
For i = 2 To Q
Select Case True
Case a(i, 2) <> "" And a(i, 3) <> "" And a(i, 4) <> ""
R(1) = 1 + R(1): b(1) = fillArray(b(1), R(1), a, i)
Case a(i, 2) <> ""
R(2) = 1 + R(2): b(2) = fillArray(b(2), R(2), a, i)
End Select
Next
Rem -----------------------------------\
With Sheets("New Orders")
.Select
.Range("A3").CurrentRegion.Offset(1).Delete xlShiftUp
.Range("A4").Resize(R(1), 4) = b(1)
End With
Rem -----------------------------------\
With Sheets("Incomplete Orders")
.Range("A1").CurrentRegion.Offset(1).Delete xlShiftUp
.Range("A2").Resize(R(2), 4) = b(2)
End With
End Sub
*I am trying to use the code below to format and clean data it keeps giving me an error message "Sub or function not defined"

How do i avoid "Subscript out of Range?

I am having an issue with the "Subscript out of Range" error message. I got some help writing a code that loops a long list of stocks. The code basically makes all of the vectors even so i can use it in a panel data setting.
The loop stops after 4 stocks and gives me a "Subscript out of Range" error.
I can run the code over the first 95 "i" i.e. if i transform the first part:
For i = 4 To 95
If Cells(i, 1) <> Cells(i - 1, 1) Then Clean_Stock_2 (i)
Code:
**Sub Outer_Loop()
For i = 4 To Cells(Rows.Count, 1).End(xlUp).Row**
If Cells(i, 1) <> Cells(i - 1, 1) Then Clean_Stock_2 (i)
Next i
End Sub
Sub Clean_Stock_2(ByVal r As Long)
Dim Stock(31, 5)
Dim Quarter(31)
Dim Bo As Boolean
Charge = 0
'Frame
For i = 0 To 31
Stock(i, 0) = Cells(r, 1)
Stock(i, 1) = Cells(r, 2)
Stock(i, 2) = Cells(r, 3)
Stock(i, 5) = "Q" & Format(DateAdd("q", i, #1/1/2011#), "q-YYYY")
Quarter(i) = Stock(i, 5)
Next i
'Data
Do While Cells(r, 1) = Stock(0, 0)
Qu = "Q" & Format(Cells(r, 4), "q-YYYY")
rr = Application.Match(Qu, Quarter, 0)
If Not IsError(rr) Then
Stock(rr, 3) = Cells(r, 4)
Stock(rr, 4) = Cells(r, 5)
If Not Bo Then Charge = Stock(rr, 4): Bo = True
End If
r = r + 1
Loop
'fill
For i = 0 To 31
If Stock(i, 4) = 0 Then
Stock(i, 4) = Charge
Else
Charge = Stock(i, 4)
End If
Next i
'Output
lr = Cells(Rows.Count, "I").End(xlUp).Row + 1
lr = IIf(lr < 3, 3, lr)
Cells(lr, "I").Resize(32, 6) = Stock
End Sub

Shuffling a 2D array

I have the follow script to put a list of people with there know skills in an array and then match the first match with a customer with the same skill. Every time it runs the results are the same. I would like to have it be a random order of the array, but keeping the two columns in the array together. How can I shuffle(rearrange) the array that keeps the rows in the array the same? Or would it be better to erase the array, randomly sort the columns and set the array back up?
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
p = 0
o = 0
For i = 2 To 920
If Cells(i, 12).Value <> Cells(i - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(i, 12).Value
arOne(p, 1) = Cells(i, 13).Value
o = 2
Else
arOne(p, o) = Cells(i, 13).Value
o = o + 1
End If
Next
For i = 2 To 612
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & i), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(i, 2).Value Then
Cells(i, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
GoTo NextIR
End If
Next j
End If
End If
Next o
NextIR:
Next i
End Sub
Multiple loops and multiple access to range objects makes your code very, very slow (I don't know if performance is important).
I would read all necessary data to arrays and use filter and rnd to get a random person with the relevant skill:
Option Explicit
Sub PeopleBusiness()
Dim People, Customers, FilterArray
Dim I As Long, Idx As Long
People = Application.Transpose([L2:L920 & "|" & M2:M8])
Customers = Range("A2:C612").Value2
For I = 1 To UBound(Customers, 1)
FilterArray = Filter(People, Customers(I, 2))
If UBound(FilterArray) > -1 Then
Idx = Round(Rnd() * UBound(FilterArray), 0)
Customers(I, 3) = Left(FilterArray(Idx), InStr(1, FilterArray(Idx), "|") - 1)
End If
Next I
Range("A2:C612").Value = Customers
End Sub
I was able to get done what I needed by erasing the array and redimming it after sorting the data based on a rand() number in the table. It takes about 15 minutes to run 7000 assignment but it is a lot better than 7+ hours it takes to do manually.
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
Application.Calculation = xlAutomatic
StartTime = Timer
NextIR:
ReDim arOne(1000, 15)
p = 0
o = 0
QAlr = Sheets("Sheet1").Range("L" & Rows.Count).End(xlUp).Row
For I = 2 To QAlr
If Cells(I, 12).Value <> Cells(I - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(I, 12).Value
arOne(p, 1) = Cells(I, 13).Value
o = 2
Else
arOne(p, o) = Cells(I, 13).Value
o = o + 1
End If
Next
AQAlr = Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Row
AgtLr = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For I = AQAlr + 1 To AgtLr
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & I), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(I, 2).Value Then
Cells(I, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
Erase arOne()
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Add _
Key:=Range("Table1[[#All],[Random '#]]"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
GoTo NextIR
End If
Next j
End If
End If
Next o
Next I
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
MsgBox "Assignments completed in " & MinutesElapsed & " minutes", vbInformation
End Sub
Not entirely sure I got your set-up right but you can try this:
Option Explicit
Sub Assign()
Randomize
Range("C2", Range("C" & Rows.Count).End(xlUp)).ClearContents
Dim R1 As Range: Set R1 = Range("L2:M920") 'People skill table
Dim R2 As Range: Set R2 = Range("A2:B612") 'Cusotmers skill talbe
Dim D0 As Object: Set D0 = CreateObject("scripting.dictionary")
Dim i As Integer, j As Integer, Rand as Integer
For i = 1 To R2.Rows.Count
Rand = Int(R1.Rows.Count * Rnd + 1)
For j = 1 To R1.Rows.Count
If R1.Cells(Rand, 2) = R2(i, 2) And Not D0.exists(Rand) Then
R2.Cells(i, 2).Offset(0, 1) = R1(Rand, 1)
D0.Add Rand, Rand
Exit For
End If
Rand = (Rand Mod R1.Rows.Count) + 1
Next j
Next i
End Sub
The idea is to check the people skill list starting from a random point and making sure a key is not used twice.
EDIT:
According to your comment I assume a "people / skill" can then be assigned more than once as there are 7000+ customers ?
Code below randomly assign with a fairly good distribution 1500 peoples to 7000 customers in +/- 1 second.
Have a try and see if you can adapt it to your project.
Option Explicit
Sub Assign()
Application.ScreenUpdating = False
Dim Start: Start = Timer
Randomize
Range("C2:C99999").ClearContents
Dim D1 As Object
Dim R1 As Range: Set R1 = Range("L2", Range("M" & Rows.Count).End(xlUp))
Dim R2 As Range: Set R2 = Range("A2", Range("B" & Rows.Count).End(xlUp))
Dim T1: T1 = R1
Dim T2: T2 = R2
Dim T3()
Dim a As Integer: a = 1
Dim i As Integer, j As Integer, k As Integer, Rnd_Val As Integer, j_loop As Integer
For i = 1 To (Int(R2.Rows.Count / R1.Rows.Count) + 1)
Set D1 = CreateObject("scripting.dictionary")
For j = (R1.Rows.Count * i - R1.Rows.Count + 1) To R1.Rows.Count * i
ReDim Preserve T3(1 To j)
Rnd_Val = Int(Rnd * R1.Rows.Count + 1)
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) And Not D1.exists(Rnd_Val) And T3(j) = "" Then
T3(j) = T1(Rnd_Val, 1)
D1.Add Rnd_Val, Rnd_Val
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
If T3(j) = "" Then
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) Then
T3(j) = T1(Rnd_Val, 1)
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
End If
a = a + 1
If a > R2.Rows.Count Then GoTo EndLoop
Next j
Set D1 = Nothing
Next i
EndLoop:
Range("C2").Resize(UBound(T3), 1) = Application.Transpose(T3)
Debug.Print Timer - Start
Application.ScreenUpdating = True
End Sub

Redundancy in logic for excel VBA

Please see the image attached -
My requirement is -
"If status null and Ref No. not unique then
check value2. If value2 not present, check value1 and take average
Example: For ref number = 1, calculated value is (50+10)/2 = 30 "
"if status is selected or Ref no is unique then
copy from value2, if not present then copy from value1
Example: For Ref No 3, value is 100 and for Ref No 4, value is 20
Total value= 100+30+20 = 150
My attempt
For I = 2 To lrow 'sheets all have headers that are 2 rows
'unique
If Application.WorksheetFunction.CountIf(ws.Range("A" & fRow, "A" & lrow), ws.Range("A" & I)) = 1 Then
If (ws.Range("AW" & I) <> "") Then 'AW has value2
calc = calc + ws.Range("AW" & I).Value
Else: calc = calc + ws.Range("AV" & I).Value 'AV has value1
End If
'not unique
Else
'selected
If ws.Range("AY" & I) = "Selected" Then 'AY has status (Selected/Null)
If (ws.Range("AW" & I) <> "") Then
calc = calc + ws.Range("AW" & I).Value
Else: calc = calc + ws.Range("AV" & I).Value
End If
'not selected
Else
If (ws.Range("AW" & I) <> "") Then
calc1 = calc1 + ws.Range("AW" & I).Value
Else: calc1 = calc1 + ws.Range("AV" & I).Value
End If
calc1 = calc1/Application.WorksheetFunction.CountIf(ws.Range("A" & fRow, "A" & lrow), ws.Range("A" & I))
End If
End If
My problem is -
Getting the Ref No 3 twice in my logic.
Not able to calculate the correct average.
How can I get the correct output? Thanks.
Using a SQL statement against the worksheet
If I understand your requirements, they are as follows:
For each Ref no, you want
the average of
value2 if it exists, otherwise value1
where the status is selected, or
there is no status = selected for this Ref no
I would open an ADODB Recordset against the data, with the following SQL:
SELECT [Ref no], Avg(Iif(value2 IS NOT NULL, value2, value1)) AS Result
FROM Sheet1
LEFT JOIN (
SELECT DISTINCT [Ref No]
FROM Sheet1
WHERE status = "selected"
) t1 ON Sheet1.[Ref no] = t1.[Ref no]
WHERE Sheet1.status="selected" OR t1.[Ref no] IS NULL
GROUP BY [Ref no]
Using nested Scripting.Dictionary
If SQL is not your thing, then you could something like the following:
'Define names for the columns; much easier to read row(RefNo) then arr(0)
Const refNo = 1
Const status = 3
Const value1 = 5
Const value2 = 6
'For each RefNo, we have to store 3 pieces of information:
' whether any of the rows are selected
' the sum of the values
' the count of the values
Dim aggregates As New Scripting.Dictionary
Dim arr() As Variant
arr = Sheet1.UsedRange.Value
Dim maxRow As Long
maxRow = UBound(arr, 1)
Dim i As Long
For i = 2 To maxRow 'exclude the column headers in the first row
Dim row() As Variant
row = GetRow(arr, i)
'Get the current value of the row
Dim currentValue As Integer
currentValue = row(value1)
If row(value2) <> Empty Then currentValue = row(value2)
'Ensures the dictionary always has a record corresponding to the RefNo
If Not aggregates.Exists(row(refNo)) Then Set aggregates(row(refNo)) = InitDictionary
Dim hasPreviousSelected As Boolean
hasPreviousSelected = aggregates(row(refNo))("selected")
If row(status) = "selected" Then
If Not hasPreviousSelected Then
'throw away any previous sum and count; they are from unselected rows
Set aggregates(row(refNo)) = InitDictionary(True)
End If
End If
'only include currently seleced refNos, or refNos which weren't previously selected,
If row(status) = "selected" Or Not hasPreviousSelected Then
aggregates(row(refNo))("sum") = aggregates(row(refNo))("sum") + currentValue
aggregates(row(refNo))("count") = aggregates(row(refNo))("count") + 1
End If
Next
Dim key As Variant
For Each key In aggregates
Debug.Print key, aggregates(key)("sum") / aggregates(key)("count")
Next
with the following two helper functions:
Function GetRow(arr() As Variant, rowIndex As Long) As Variant()
Dim ret() As Variant
Dim lowerbound As Long, upperbound As Long
lowerbound = LBound(arr, 2)
upperbound = UBound(arr, 2)
ReDim ret(1 To UBound(arr, 2))
Dim i As Long
For i = lowerbound To upperbound
ret(i) = arr(rowIndex, i)
Next
GetRow = ret
End Function
Function InitDictionary(Optional selected As Boolean = False) As Scripting.Dictionary
Set InitDictionary = New Scripting.Dictionary
InitDictionary.Add "selected", selected
InitDictionary.Add "sum", 0
InitDictionary.Add "count", 0
End Function
Explanation of SQL
For each Ref no, you want
Group the records by Ref no, using the GROUP BY clause
the average of
We'll return both the Ref no and the average -- SELECT [Ref no], Avg(...)
value2 if it exists, otherwise value1
Iif(value2 IS NOT NULL, value2, value1)
where the status is selected, or
WHERE Sheet1.status="selected" OR
there is no status = selected for this Ref no
We get a list of (unique -- DISTINCT) Ref nos that have status = "selected":
SELECT DISTINCT [Ref No]
FROM Sheet1
WHERE status = "selected"
and give it a name (AS t1) so we can refer to it separately from the main list (Sheet1)
Then we connect, or join (JOIN) that sublist to the main list, where the [Ref no] is the same in both (ON Sheet1.[Ref no] = t1.[Ref no]).
A simple JOIN is an INNER JOIN, where the records on both sides of the connection have to match. What we want in this case, is the records on the main list which do not match the records in the sublist. In order to see such records, we can use a LEFT JOIN, which displays all the records on the left side, and only those records on the right side that match.
We can then filter out the records that do match, using OR t1.[Ref no] IS NULL.
There must be a more concise way, but I think this does what you want. It is based on your example, so data in A1:F6 so will need amending.
Sub x()
Dim v2() As Variant, v1, i As Long, n As Long, d As Double
v1 = Sheet1.Range("A1:F6").Value
ReDim v2(1 To UBound(v1, 1), 1 To 5) 'ref/count/null/value null/value selected
With CreateObject("Scripting.Dictionary")
For i = 2 To UBound(v1, 1)
If Not .Exists(v1(i, 1)) Then
n = n + 1
v2(n, 1) = v1(i, 1)
v2(n, 2) = v2(n, 2) + 1
If v1(i, 3) = "" Then
v2(n, 3) = v2(n, 3) + 1
v2(n, 4) = IIf(v1(i, 6) = "", v1(i, 5), v1(i, 6))
ElseIf v1(i, 3) = "selected" Then
v2(n, 5) = IIf(v1(i, 6) = "", v1(i, 5), v1(i, 6))
End If
.Add v1(i, 1), n
ElseIf .Exists(v1(i, 1)) Then
v2(.Item(v1(i, 1)), 2) = v2(.Item(v1(i, 1)), 2) + 1
If v1(i, 3) = "" Then
v2(.Item(v1(i, 1)), 3) = v2(.Item(v1(i, 1)), 3) + 1
If v1(i, 6) = "" Then
v2(.Item(v1(i, 1)), 4) = v2(.Item(v1(i, 1)), 4) + v1(i, 5)
Else
v2(.Item(v1(i, 1)), 4) = v2(.Item(v1(i, 1)), 4) + v1(i, 6)
End If
Else
If v1(i, 6) = "" Then
v2(.Item(v1(i, 1)), 5) = v2(.Item(v1(i, 1)), 5) + v1(i, 5)
Else
v2(.Item(v1(i, 1)), 5) = v2(.Item(v1(i, 1)), 5) + v1(i, 6)
End If
End If
End If
Next i
End With
For i = LBound(v2, 1) To UBound(v2, 1)
If v2(i, 2) > 1 And v2(i, 3) = v2(i, 2) Then
d = d + v2(i, 4) / v2(i, 2)
End If
If v2(i, 2) > 1 And v2(i, 3) < v2(i, 2) Then
d = d + v2(i, 5) / (v2(i, 2) - v2(i, 3))
End If
If v2(i, 2) = 1 And v2(i, 3) = v2(i, 2) Then
d = d + v2(i, 4) / v2(i, 2)
End If
Next i
MsgBox "Total = " & d
End Sub

Need to choose files manually instead of directing the vb code to a folderpath

I did a vb code which is reading multiple text files from a folder and then parsing specific data from it. In the code I have hard coded a folderpath strPath = "C:\Users\smim\Desktop\Mim\Excel\". Now I would like to be able to choose the folder and files manually instead of hard coding the folder path. Here is my code :
Sub Parse()
Dim ws As Worksheet
Dim MyData As String, strData() As String
Dim WriteToRow As Long, i As Long
Dim strCurrentTxtFile As String
Dim count As Variant, yellow As Variant, red As Variant,
Dim YellowC As Variant,RedC As Variant, filecounter As Variant
Dim strPath As String
Application.ScreenUpdating = False
count = 0
red = 0
yellow = 0
YellowC = 0
RedC = 0
strPath = "C:\Users\smim\Desktop\Mim\Excel\"
'Set Book3 = Sheets("Sheet1")
Set ws = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
MsgBox ("Started")
'~~> Start from Row 1
'WriteToRow = 1
Cells(3, 1) = "Error"
Cells(3, 1).Interior.ColorIndex = 3
Cells(3, 2) = "Warnings"
Cells(3, 2).Interior.ColorIndex = 6
Cells(1, 3) = "Error"
Cells(1, 3).Interior.ColorIndex = 3
Cells(2, 3) = "Warnings"
Cells(2, 3).Interior.ColorIndex = 6
strCurrentTxtFile = Dir(strPath & "test_*.txt")
' MsgBox (strCurrentTxtFile)
'~~> Looping through all text files in a folder
Do While strCurrentTxtFile <> ""
Dim list() As String
'~~> Open the file in 1 go to read it into an array
Open strPath & strCurrentTxtFile For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
strData() = Split(MyData, vbLf)
LineCount = UBound(strData)
' MsgBox (LineCount)
'Assigning length of the list array
ReDim Preserve list(LineCount + 1)
For x = 0 To (LineCount - 1)
'For x = LBound(strData) To UBound(strData)
'Parsing each line to get the result only ( after = sign)
s = Split(strData(x), "=")
b = UBound(s)
'MsgBox (s(1))
'Assigning Values to the list array
list(x) = s(1)
Next
'MsgBox ("This is list" & list(2))
'Active Cell 2
Range("A2").Activate
'Get row number
dblRowNo = ActiveCell.Row
'Get col number
dblColNo = ActiveCell.Column
'MsgBox (dblColNo)
' ReDim Preserve list(LineCount)
For i = 0 To (LineCount - 1)
Cells(3, 3 + i + 1).Value = i
'Looping and assigning Values to the Cell
'For i = LBound(strData) To UBound(strData)
tempParsing = Split(list(i), ":")
' MsgBox (tempParsing(0))
If tempParsing(0) > 0 And tempParsing(0) < 10 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 6
yellow = yellow + 1
ElseIf tempParsing(0) >= 10 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 3
red = red + 1
ElseIf tempParsing(0) = 0 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 0
End If
'Looping and assigning Values to the Cell
' For i = LBound(strData) To UBound(strData)
Cells(dblRowNo + count + 2, dblColNo + 1) = yellow
Cells(dblRowNo + count + 2, dblColNo) = red
Cells(dblRowNo + count + 2, dblColNo + i + 3).Value = list(i)
Next
Cells(3 + count + 1, 3).Value = count
count = count + 1
yellow = 0
red = 0
strCurrentTxtFile = Dir
Loop
For t = 4 To 175
If Cells(t, 1).Value > 0 Then
Cells(t, 1).Interior.ColorIndex = 3
End If
If Cells(t, 2).Value > 0 Then
Cells(t, 2).Interior.ColorIndex = 6
End If
Next
'Cells(9, 1) = "linecount = "
'Cells(9, 2) = LineCount
MsgBox "Done"
For f = 4 To 175
If Cells(f, 4).Interior.ColorIndex = 6 Then
YellowC = YellowC + 1
ElseIf Cells(f, 4).Interior.ColorIndex = 3 Then
RedC = RedC + 1
End If
Next
For g = 4 To 175
If Cells(g, 7).Interior.ColorIndex = 6 Then
YellowC = YellowC + 1
ElseIf Cells(g, 7).Interior.ColorIndex = 3 Then
RedC = RedC + 1
End If
Next
For u = 0 To (LineCount - 1)
Cells(dblRowNo, dblColNo + u + 3) = YellowC
Cells(1, dblColNo + u + 3) = RedC
Next
YellowC = 0
RedC = 0
Application.ScreenUpdating = True
End Sub

Resources