I have a function in VBA that is supposed to sort text based on a "Bubble sort". If the text were just text then it would be fine, but my text is actually an alpha numeric string. I tried to rewrite it to account for the number part but something is still off and I can't seem to figure out what. Please help!!
Dim alphaCurr As String
Dim alphaNext As String
Dim rowCurr As FsChartRow
Dim rowNext As FsChartRow
Dim c As Integer
Dim n As Integer
Dim vTemp As Variant
For c = 1 To rows.count - 1
Set rowCurr = rows(c)
alphaCurr = GetAlpha(rowCurr.label)
For n = c + 1 To rows.count
Set rowNext = rows(n)
alphaNext = GetAlpha(rowNext.label)
If alphaCurr > alphaNext Then
Set vTemp = rows(n)
rows.Remove n
rows.Add vTemp, , c
End If
Next n
Next c
Dim numCurr As Integer
Dim numNext As Integer
Dim loopCount As Integer
For c = 1 To rows.count - 1
Set rowCurr = rows(c)
alphaCurr = GetAlpha(rowCurr.label)
numCurr = GetNumeric(rowCurr.label)
For n = c + 1 To rows.count
Set rowNext = rows(n)
alphaNext = GetAlpha(rowNext.label)
numNext = GetNumeric(rowNext.label)
If alphaCurr = alphaNext Then
If numCurr > numNext Then
Set vTemp = rows(n)
rows.Remove n
rows.Add vTemp, , c
End If
End If
Next n
Next c
The results I am getting are as follows:
"BK1"
"BK2"
"FB1"
"FB4"
"FB3"
"FB5"
"FB6"
"FB2"
"FJ2"
"FJ1"
"FJ3"
"FJ4"
"..."
"FJ15"
"RB1"
"H1"
"H2"
Thank for your help!
I have found a solution to my problem. I still could not get the bubble sort to work, so I created my own, that takes no more time to run then the bubble sort. I'll post in case it helps anyone.
Private Function SortFsChartRow(collection As collection) As collection
Dim min As Integer
Dim max As Integer
Dim x As Integer
Dim y As Integer
Dim rowCurr As FsChartRow
Dim numCurr As Integer
Dim rowMin As FsChartRow
Dim rowMax As FsChartRow
Dim search As Integer
Dim sorted As collection
Set sorted = New collection
min = 100
max = 0
For x = 1 To collection.count
Set rowCurr = collection(x)
numCurr = GetNumeric(rowCurr.label)
If numCurr > max Then
max = numCurr
Set rowMax = rowCurr
End If
If numCurr < min Then
min = numCurr
Set rowMin = rowCurr
End If
Next x
search = min
For y = 0 To max
For x = 1 To collection.count
Set rowCurr = collection(x)
numCurr = GetNumeric(rowCurr.label)
If numCurr = search Then
sorted.Add rowCurr
Exit For
End If
Next
search = search + 1
Next y
Set SortFsChartRow = sorted
End Function
Related
The following code splits each lines into words and store the first words in each line into array list and the second words into another array list and so on. Then it selects the most frequent word from each list as correct word.
Module Module1
Sub Main()
Dim correctLine As String = ""
Dim line1 As String = "Canda has more than ones official language"
Dim line2 As String = "Canada has more than one oficial languages"
Dim line3 As String = "Canada has nore than one official lnguage"
Dim line4 As String = "Canada has nore than one offical language"
Dim wordsOfLine1() As String = line1.Split(" ")
Dim wordsOfLine2() As String = line2.Split(" ")
Dim wordsOfLine3() As String = line3.Split(" ")
Dim wordsOfLine4() As String = line4.Split(" ")
For i As Integer = 0 To wordsOfLine1.Length - 1
Dim wordAllLinesTemp As New List(Of String)(New String() {wordsOfLine1(i), wordsOfLine2(i), wordsOfLine3(i), wordsOfLine4(i)})
Dim counts = From n In wordAllLinesTemp
Group n By n Into Group
Order By Group.Count() Descending
Select Group.First
correctLine = correctLine & counts.First & " "
Next
correctLine = correctLine.Remove(correctLine.Length - 1)
Console.WriteLine(correctLine)
Console.ReadKey()
End Sub
End Module
My Question: How can I make it works with lines of different number of words. I mean that the length of each lines here is 7 words and the for loop works with this length (length-1). Suppose that line 3 contains 5 words.
EDIT: Accidentally had correctIndex where shortest should have been.
From what I can tell you are trying to see which line is the closest to the correctLine.
You can get the levenshtein distance using the following code:
Public Function LevDist(ByVal s As String,
ByVal t As String) As Integer
Dim n As Integer = s.Length
Dim m As Integer = t.Length
Dim d(n + 1, m + 1) As Integer
If n = 0 Then
Return m
End If
If m = 0 Then
Return n
End If
Dim i As Integer
Dim j As Integer
For i = 0 To n
d(i, 0) = i
Next
For j = 0 To m
d(0, j) = j
Next
For i = 1 To n
For j = 1 To m
Dim cost As Integer
If t(j - 1) = s(i - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1),
d(i - 1, j - 1) + cost)
Next
Next
Return d(n, m)
End Function
And then, this would be used to figure out which line is closest:
Dim correctLine As String = ""
Dim line1 As String = "Canda has more than ones official language"
Dim line2 As String = "Canada has more than one oficial languages"
Dim line3 As String = "Canada has nore than one official lnguage"
Dim line4 As String = "Canada has nore than one offical language"
Dim lineArray As new ArrayList
Dim countArray As new ArrayList
lineArray.Add(line1)
lineArray.Add(line2)
lineArray.Add(line3)
lineArray.Add(line4)
For i = 0 To lineArray.Count - 1
countArray.Add(LevDist(lineArray(i), correctLine))
Next
Dim shortest As Integer = Integer.MaxValue
Dim correctIndex As Integer = 0
For i = 0 To countArray.Count - 1
If countArray(i) <= shortest Then
correctIndex = i
shortest = countArray(i)
End If
Next
Console.WriteLine(lineArray(correctIndex))
Main point of this function is to return the most common movie genre.
Function MoviesByGenre(genreRng As Range) As String
Dim genreList(1 To 4) As String
Dim current As Integer
current = 1
For i = 1 To genreRng.count
Dim found As Integer
found = 0
For j = 1 To current
If genreList(j) = genreRng.Cells(i) Then
found = 1
Exit For
End If
Next j
If found = 0 Then
genreList(current) = genreRng.Cells(i)
current = current + 1
End If
Next i
Dim genreCount(1 To 4) As Integer
For i = 1 To 4
Dim count As Integer
count = 0
For j = 1 To genreRng.count
If genreRng.Cells(j) = genreList(i) Then
count = count + 1
End If
Next j
genreCount(i) = count
Next i
MoviesByGenre = FindMax(genreCount, genreList)
End Function
Now my FindMax function looks like this:
Function FindMax(valueArray, nameArray) As String
Dim max As Double
max = valueArray(LBound(valueArray))
For i = LBound(valueArray) + 1 To UBound(valueArray)
If valueArray(i) > valueArray(max) Then
max = i
End If
Next i
FindMax = nameArray(max)
End Function
FindMax appears to work well in other areas, but depending on the range I use for MoviesByGenre, it may or may not work. (sometimes it'll give me #VALUE!, other times it'll give me the actual most common movie genre, and i'm not sure why.) I'm using Excel 2016 for MacOS.
Do you mean something like that
Sub Test()
Dim a As Variant
a = Range("A1:A7").Value
MsgBox FindMax(a)
End Sub
Function FindMax(valueArray) As String
Dim max As Double
Dim i As Long
max = valueArray(LBound(valueArray), 1)
For i = LBound(valueArray) + 1 To UBound(valueArray)
If valueArray(i, 1) > max Then
max = valueArray(i, 1)
End If
Next i
FindMax = max
End Function
Dim Var_1 As String
Dim Var_2 As String
Dim Var_3 As String
Dim Var_4 As String
Dim Var_5 As String
Dim Var_6 As String
Dim Var_7 As String
Dim Var_8 As String
Dim Var_9 As String
Dim Var_10 As String
Dim Var_11 As String
Dim Var_12 As String
Dim Var_13 As String
Dim Var_14 As String
Dim Var_15 As String
Dim Var_16 As String
Dim Var_17 As String
Dim Var_18 As String
Dim Var_19 As String
Dim Var_20 As String
Dim Var_21 As String
Dim Var_22 As String
Dim Var_23 As String
Dim Var_24 As String
Dim Var_25 As String
Dim Var_26 As String
Dim Var_27 As String
Dim Var_28 As String
Dim Var_29 As String
Var_1 = "Ex-Bidadi"
Var_2 = "Ex-Hospet"
Var_3 = "Ex-Chennai"
Var_4 = "Ex-Coimbatore"
Var_5 = "Ex-Gangaikondan"
Var_6 = "Ex-Pune"
Var_7 = "Ex-Goa"
Var_8 = "Ex-Mumbai"
Var_9 = "Ex-Nashik"
Var_10 = "Ex-Aurangabad"
Var_11 = "Ex-Goblej"
Var_12 = "Ex-Hyderabad"
Var_13 = Ex - Vizag
Var_14 = "Ex-Vijayawada"
Var_15 = "Ex-Chittoor"
Var_16 = "Ex - Siliguri"
Var_17 = "Ex-odhisha"
Var_18 = "Ex-Jharkhand"
Var_19 = "Ex-Bihar"
Var_20 = "Ex-NorthEast"
Var_21 = "Ex-Delhi"
Var_22 = "Ex-Udaipur"
Var_23 = "Ex-Jammu"
Var_24 = "Ex-Haridwar"
Var_25 = "Ex-Dasna"
Var_26 = "Ex-Kanpur"
Var_27 = "Ex-Unnao"
Var_28 = "Ex-Var_anasi"
Var_29 = "Ex-Bhopal"
I am showing you a part of my code and i just want to known how to loop these I tried using this representation
For n = 1 to 29
For i = 3 To 445
For m = 28 To 40
ActiveWorkbook.Sheets("Var_" & n).Cells(i, m) = 999999
least(i, m, n) = ActiveWorkbook.Sheets("Var_" & n).Cells(i, m)
Next m
Next i
Next n
I have defined the least(i,m,n) array but the loop is showing an error at the subscript is out of Range I have tried using all the possibilities but the loop doesn't work
You need to store the sheet names in an array:
Var = Array("Ex-Bidadi", "Ex-Hospet", "Ex-Chennai", "Ex-Coimbatore", "Ex-Gangaikondan", "Ex-Pune", "Ex-Goa", "Ex-Mumbai", "Ex-Nashik", "Ex-Aurangabad", "Ex-Goblej", "Ex-Hyderabad", "Ex - Vizag", "Ex-Vijayawada", "Ex-Chittoor", "Ex - Siliguri", "Ex-odhisha", "Ex-Jharkhand", "Ex-Bihar", "Ex-NorthEast", "Ex-Delhi", "Ex-Udaipur", "Ex-Jammu", "Ex-Haridwar", "Ex-Dasna", "Ex-Kanpur", "Ex-Unnao", "Ex-Var_anasi", "Ex-Bhopal")
Then inside your loop use the following:
least(i, m, n) = ActiveWorkbook.Sheets(Var(n)).Cells(i, m)
Create an array of your sheet
Dim Var
Var = Array("Ex-Bidadi"", "Ex-Hospet", "Ex-Chennai" ... till the last sheet)
Count the number of sheets that included on your array. Array starts at index 0.
For n = 0 to 28 '29 sheets less 1, because of the array index 0
For i = 3 To 445
For m = 28 To 40
ActiveWorkbook.Sheets(Var(n)).Cells(i, m) = 999999
least(i, m, n) = ActiveWorkbook.Sheets(Var(n)).Cells(i, m)
Next m
Next i
Next n
Loop through all sheets and pick just the ones you need in a SELECT CASE statement:
Sub Test()
Dim wrkSht As Worksheet
Dim i As Long, m As Long
Dim cLeast As Collection
Set cLeast = New Collection
For Each wrkSht In ThisWorkbook.Worksheets
'NB: If you want sheets that start with "Ex-" use commented lines instead:
'Select Case Left(wrkSht.Name, 3)
Select Case wrkSht.Name
'Case "Ex-"
Case "Ex-Bidadi", "Ex-Hospet", "Ex-Chnnai"
For i = 3 To 445
For m = 28 To 40
cLeast.Add wrkSht.Cells(i, m), wrkSht.Name & "|" & i & "|" & m
Next m
Next i
Case Else
'Code if not the sheet you're after.
End Select
Next wrkSht
Debug.Print cLeast("Ex-Bidadi|3|28")
End Sub
NB: I've used a collection in the loop as not sure what you're after. Dictionaries are probably the better way to go.
I'm able to get the correct row count, but the problem is when I run through the loop.
OrdNum = dgvWsNorth.Rows(i).Cells("ORDNUM").Value.ToString()
This line will loop through all visible and non visible rows = to the row count.
I need it to loop through only the visible rows = to the row count.
Dim AllRows As Integer = dgvWsNorth.Rows.GetRowCount(DataGridViewElementStates.Visible)
Dim OrdNum As Integer
Dim LinNum As Integer
Dim UnitPriority As Integer
Dim Ws_N As Integer = My.Settings.NorthLine
For i = 0 To AllRows - 1
OrdNum = dgvWsNorth.Rows(i).Cells("ORDNUM").Value.ToString()
LinNum = dgvWsNorth.Rows(i).Cells("LINE").Value.ToString()
If IsDBNull(dgvWsNorth.Rows(i).Cells("UNIT_PRIORITY").Value) Then
UnitPriority = 999
Else
UnitPriority = dgvWsNorth.Rows(i).Cells("UNIT_PRIORITY").Value.ToString()
End If
clsScheduler.UPDATE_ASSIGNED_WS(Ws_N, OrdNum, LinNum, clsLogin.plant_id, clsLogin.dept_id, UnitPriority)
Next
How about looping through all rows, and only counting the rows that are visible?
Dim i = 0
Dim OrdNum As Integer
Dim LinNum As Integer
Dim UnitPriority As Integer
Dim Ws_N As Integer = My.Settings.NorthLine
For Each r As DataGridViewRow In dgvWsNorth.Rows
If r.Visible Then
OrdNum = r.Cells("ORDNUM").Value.ToString()
LinNum = r.Cells("LINE").Value.ToString()
If IsDBNull(r.Cells("UNIT_PRIORITY").Value) Then
UnitPriority = 999
Else
UnitPriority = r.Cells("UNIT_PRIORITY").Value.ToString()
End If
clsScheduler.UPDATE_ASSIGNED_WS(Ws_N, OrdNum, LinNum, clsLogin.plant_id, clsLogin.dept_id, UnitPriority)
i += 1
End If
Next
Actually, I decided to give this a shot and I think you can do this with a Lambda on your for each statement
Instead of a for next loop use a for each with a lambda expression
For each r as datagridviewrow in DataGridView1.Rows.Cast(Of Datagridviewrow)().Where(Function(row) row.Visible = true)
... your loop code using r instead of rows(i)
Next
This should only iterate through rows that are visible.
I have an array of integers in VBA from which I would like to get the upper and lower quartiles.
I would like to use this method to get them: https://msdn.microsoft.com/en-us/library/office/ff836118.aspx
The documentation suggests you can use an array to do this, but when I try to run my code (below) I get an error saying Unable to get the Quartile property of the WorksheetFunction class
Please assist.
Dim totalsalesthatday() As String
Dim doINeedTo As Boolean
Dim totalsalesthatdayAverage As Integer
Dim randomnumberthingy As Integer
Dim quartile1 As Integer
Dim quartile3 As Integer
Dim iqr As Integer
Dim upper As Integer
Dim lower As Integer
quantity = 0
For Each queryaddress In worksheetname.Range("A2:A21")
query = queryaddress.Value
offsetnum = 0
If offsetnum = 0 Then
doINeedTo = True
End If
For Each daysoftheweek In Sheets
quantity = 0
If InStr(1, daysoftheweek.Name, worksheetnamename, vbTextCompare) > 0 And daysoftheweek.ListObjects.Count > 0 Then
Set itemaddress = daysoftheweek.Columns(5).Find(query, , xlValues, xlWhole)
If Not itemaddress Is Nothing Then
firstAddress = itemaddress.Address
Do
Set itemrow = itemaddress.EntireRow
quantity = quantity + itemrow.Columns(6).Value
Set itemaddress = daysoftheweek.Columns(5).FindNext(itemaddress)
Loop While Not itemaddress Is Nothing And itemaddress.Address <> firstAddress
End If
offsetnum = offsetnum + 1
ReDim Preserve totalsalesthatday(offsetnum)
totalsalesthatday(offsetnum) = daysoftheweek.ListObjects.Item(1).ListRows.Count
queryaddress.Offset(0, offsetnum).Value = quantity
worksheetname.Range("A1").Offset(0, offsetnum).Value = daysoftheweek.Name
End If
Next
If doINeedTo Then
quartile1 = WorksheetFunction.Quartile(totalsalesthatday, 1)
quartile3 = WorksheetFunction.Quartile_Inc(totalsalesthatday, 3)
iqr = quartile3 - quartile1
upper = quartile3 + (iqr * 1.5)
lower = quartile1 - (iqr * 1.5)
The error in question is at this line: quartile1 = WorksheetFunction.Quartile(totalsalesthatday, 1)
The .Quartile function parameters are an array and a double. Try changing your data types.