Macro fails to separate sequences when some values are random - excel

as a beginner in VBA programming I have a hard time figuring out what the problem is. The code works perfectly when the values ​​increase in order, but when there are values ​​in the array that are not similar then I get an error.
When the problematic values ​​are loaded, an error occurs Run time error 9, subscript out of range and this line is highlighted in the code sequenceArr(counter) = arr(i + 1) The main task of the code is to make short notations of long strings of numbers and to make a separation between different strings.
For example: i have box ID numbers: M0054515, M0054516, M0054517, M0054620, M0054621, M0054622, M0054751, M0054752, M0054753
When i run macro i get output result like this:
M0054515-517 // M0054620-622 // M0054751-753.
But when i have some random numbers in middile of ID number series i get an error... M0046552, M0047396, M0047399, M0047802, M0047803 instead of separated values i get run time error message.
At this link is an example version of my book, if anyone wants to help solve the problem.
For this job I use this code written a long time ago by another member of this forum
Sub Generate()
Dim ws As Worksheet
Dim arr() As String, result As String, letter As String, cellValue As String, tempLastElement As String
Dim lastColumn As Long, counter As Long
Dim firstColumn As Integer, targetRow As Integer, i As Integer
Set ws = Worksheets("KreirajRadniNalog")
firstColumn = 1
targetRow = 1
lastColumn = ws.Range(ws.Cells(targetRow, firstColumn), ws.Cells(targetRow, Columns.Count).End(xlToLeft).Columns).Count
ReDim arr(1 To lastColumn - firstColumn + 1)
letter = Left(ws.Cells(targetRow, firstColumn).Value, 1)
For i = 1 To UBound(arr)
cellValue = ws.Cells(targetRow, i).Value
arr(i) = Right(cellValue, Len(cellValue) - 1)
Next i
ReDim sequenceArr(1 To UBound(arr))
sequenceArr(1) = arr(1)
counter = 2
For i = 1 To UBound(arr) - 1
If CLng(arr(i)) + 1 = CLng(arr(i + 1)) Then
tempLastElement = arr(i + 1)
sequenceArr(counter) = tempLastElement
Else
counter = counter + 1
sequenceArr(counter) = arr(i + 1) '<<<this line here is highlighted
counter = counter + 1
End If
Next
ReDim Preserve sequenceArr(1 To counter)
result = ""
counter = 1
For i = 1 To UBound(sequenceArr) - 1
If counter > UBound(sequenceArr) Then Exit For
If result = "" Then
result = letter & sequenceArr(counter) & "-" & Right(sequenceArr(counter + 1), 3)
counter = counter + 2
Else
result = result & "//" & letter & sequenceArr(counter) & "-" & Right(sequenceArr(counter + 1), 3)
counter = counter + 2
End If
Next
ws.Range("C4").Value = result
End Sub

Please, try the next updated code. Since you did not answer my clarification question, I (only) hope that I could deduce what you want accomplishing...
Sub Generate()
Dim ws As Worksheet
Dim arr, sequenceArr, letter As String, cellValue As String, tempLastElement As String
Dim lastColumn As Long, counter As Long, firstColumn As Long, targetRow As Integer, i As Long, j As Long
Set ws = Worksheets("KreirajRadniNalog")
firstColumn = 1: targetRow = 1
lastColumn = ws.Range(ws.Cells(targetRow, firstColumn), ws.Cells(targetRow, Columns.Count).End(xlToLeft).Columns).Count
ReDim arr(1 To lastColumn - firstColumn + 1)
letter = Left(ws.Cells(targetRow, firstColumn).Value, 1)
For i = 1 To UBound(arr)
cellValue = ws.Cells(targetRow, i).Value
arr(i) = Right(cellValue, Len(cellValue) - 1)
Next i
ReDim sequenceArr(1 To UBound(arr))
counter = 1
For i = 1 To UBound(arr) - 1
If CLng(arr(i)) + 1 = CLng(arr(i + 1)) Then
For j = 0 To UBound(arr)
If i + j + 1 > UBound(arr) Then Exit For
If CLng(arr(i)) + j + 1 = CLng(arr(i + 1 + j)) Then
tempLastElement = arr(i + 1 + j)
Else
Exit For
End If
Next j
sequenceArr(counter) = arr(i) & "-" & Right(tempLastElement, 3)
counter = counter + 1: i = i + j
Else
sequenceArr(counter) = arr(i): counter = counter + 1
End If
Next
ReDim Preserve sequenceArr(1 To counter - 1)
ws.Range("C4").Value = letter & Join(sequenceArr, "//" & letter)
MsgBox "Success!"
End Sub
A more compact version, working with 0 based arrays:
Sub Generate2()
Dim ws As Worksheet
Dim arr, sequenceArr, letter As String, cellValue As String, tempLastElement As String
Dim lastColumn As Long, counter As Long, firstColumn As Long, targetRow As Integer, i As Long, j As Long
Set ws = Worksheets("KreirajRadniNalog")
firstColumn = 1: targetRow = 1
lastColumn = ws.Range(ws.Cells(targetRow, firstColumn), ws.Cells(targetRow, Columns.Count).End(xlToLeft).Columns).Count
letter = Left(ws.Cells(targetRow, firstColumn).Value, 1)
With Application
arr = .Transpose(.Transpose(ws.Range(ws.Cells(targetRow, firstColumn), ws.Cells(targetRow, lastColumn)).Value))
End With
arr(1) = Mid(arr(1), 2)
arr = Split(Join(arr, "|"), "|" & letter)
ReDim sequenceArr(UBound(arr))
counter = 0
For i = 0 To UBound(arr) - 1
If CLng(arr(i)) + 1 = CLng(arr(i + 1)) Then
For j = 0 To UBound(arr)
If i + j + 1 > UBound(arr) Then Exit For
If CLng(arr(i)) + j + 1 = CLng(arr(i + 1 + j)) Then
tempLastElement = arr(i + 1 + j)
Else
Exit For
End If
Next j
sequenceArr(counter) = arr(i) & "-" & Right(tempLastElement, 3)
counter = counter + 1: i = i + j
Else
sequenceArr(counter) = arr(i): counter = counter + 1
End If
Next
ReDim Preserve sequenceArr(1 To counter)
ws.Range("C4").Value = letter & Join(sequenceArr, "//" & letter)
MsgBox "Success!"
End Sub

The problem with your code is here
Else
counter = counter + 1
sequenceArr(counter) = arr(i + 1) '<<<this line here is highlighted
counter = counter + 1
End If
because for every single number the counter is incremented twice and so exceeds the array size. However you don't really need arrays
Sub Generate()
Dim ws As Worksheet, arr
Dim lastColumn As Long, letter As String, tmp As String
Dim result As String, i As Long, m As Long, n As Long
Set ws = Worksheets("KreirajRadniNalog")
Const firstColumn = 1
Const targetRow = 1
lastColumn = ws.Cells(targetRow, Columns.Count).End(xlToLeft).Column
arr = ws.Cells(targetRow, 1).Resize(, lastColumn)
result = arr(1, 1)
m = Mid(arr(1, 1), 2)
For i = 2 To UBound(arr, 2)
n = Mid(arr(1, i), 2)
If n = m + 1 Then
tmp = "-" & Right(Val(Mid(arr(1, i), 2)), 3)
Else
result = result & tmp & "//" & arr(1, i)
tmp = ""
End If
m = n
Next
result = result & tmp
ws.Range("C4").Value = result
End Sub

Related

Get all combinations of summing numbers

Column A in sheet1 has the values [1,2,3,4,5,6] in range("A1:A6") and what I am trying to do is to get all the combinations of summing each two numbers and each three numbers and each four numbers and each five numbers
This is what I did till now but the results are not as I expected
Sub Test()
Dim a, b, lr As Long, i As Long, j As Long, k As Long, ii As Long
lr = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lr
For j = i To lr
For ii = j To lr
Cells(i, ii + 1) = i & "+" & j & "+" & ii & "=" & i + j + ii
Next ii
Next j
Next i
With Range("A1").CurrentRegion
a = .Offset(, 1).Resize(, .Columns.Count - 1).Value
ReDim b(1 To UBound(a, 1) * UBound(a, 2), 1 To 1)
For i = LBound(a) To UBound(a)
For j = LBound(a, 2) To UBound(a, 2)
If a(i, j) <> "" Then
k = k + 1
b(k, 1) = a(i, j)
End If
Next j
Next i
.Cells(1, .Columns.Count + 2).Resize(k).Value = b
End With
End Sub
Example of the desired output:
Each two numbers together >>
Sub Test()
Dim a, b, lr As Long, i As Long, j As Long, k As Long, ii As Long
lr = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lr
For j = i To lr
Cells(i, j + 1) = i & "+" & j & "=" & i + j
Next j
Next i
With Range("A1").CurrentRegion
a = .Offset(, 1).Resize(, .Columns.Count - 1).Value
ReDim b(1 To UBound(a, 1) * UBound(a, 2), 1 To 1)
For i = LBound(a) To UBound(a)
For j = LBound(a, 2) To UBound(a, 2)
If a(i, j) <> "" Then
k = k + 1
b(k, 1) = a(i, j)
End If
Next j
Next i
.Cells(1, .Columns.Count + 2).Resize(k).Value = b
End With
End Sub
The results would be like that in column J
1+1=2
1+2=3
1+3=4
1+4=5
1+5=6
1+6=7
2+2=4
2+3=5
2+4=6
2+5=7
2+6=8
3+3=6
3+4=7
3+5=8
3+6=9
4+4=8
4+5=9
4+6=10
5+5=10
5+6=11
6+6=12
This is OK for each two numbers .. How can I get the results for each three numbers and for each four numbers and for each five numbers?
** #Vityata
Public Sub PrintArrayOnSingleLine(myArray As Variant)
Dim i As Long, x As Long
Dim textArray As String, temp As String
For i = LBound(myArray) To UBound(myArray)
textArray = textArray & myArray(i)
x = x + Val(myArray(i))
temp = temp & "+" & myArray(i)
Next i
Dim myLastRow As Long
myLastRow = LastRow(Worksheets(1).Name) + 1
ActiveSheet.Cells(myLastRow, 1) = Mid(temp, 2) & "=" & x
End Sub
I have edited the procedure as you told me, but just one note, I can't get the same number to be summed. Example: 1+1=2
Combination (not repeating same values):
Copy the code below and run it. Then change the variable in size = n. The given numbers are in the initialArray. In the end, instead of printing the array as a textArray, add a variable to sum it:
Sub Main()
Dim size As Long: size = 2
Dim initialArray As Variant: initialArray = Array(1, 2, 3, 4, 5, 6)
Dim arr As Variant: ReDim arr(size - 1)
Dim n As Long: n = UBound(arr) + 1
EmbeddedLoops 0, size, initialArray, n, arr
End Sub
Function EmbeddedLoops(index As Long, size As Long, initialArray As Variant, n As Long, arr As Variant)
Dim p As Variant
If index >= size Then
If Not AnyValueBiggerThanNext(arr) And Not AnyValueIsRepeated(arr) Then
PrintArrayOnSingleLine arr
End If
Else
For Each p In initialArray
arr(index) = p
EmbeddedLoops index + 1, size, initialArray, n, arr
Next p
End If
End Function
Public Function AnyValueBiggerThanNext(arr As Variant) As Boolean
Dim i As Long
For i = LBound(arr) To UBound(arr) - 1
If arr(i) > arr(i + 1) Then
AnyValueBiggerThanNext = True
Exit Function
End If
Next i
AnyValueBiggerThanNext = False
End Function
Public Function AnyValueIsRepeated(arr As Variant) As Boolean
On Error GoTo AnyValueIsRepeated_Error:
Dim element As Variant
Dim testCollection As New Collection
For Each element In arr
testCollection.Add "item", CStr(element)
Next element
AnyValueIsRepeated = False
On Error GoTo 0
Exit Function
AnyValueIsRepeated_Error:
AnyValueIsRepeated = True
End Function
Public Sub PrintArrayOnSingleLine(myArray As Variant)
Dim i As Long
Dim textArray As String
For i = LBound(myArray) To UBound(myArray)
textArray = textArray & myArray(i)
Next i
Debug.Print textArray
End Sub
Permutation (repeating same values)
Sub Main()
Static size As Long
Static c As Variant
Static arr As Variant
Static n As Long
size = 3
c = Array(1, 2, 3, 4, 5, 6)
n = UBound(c) + 1
ReDim arr(size - 1)
EmbeddedLoops 0, size, c, n, arr
End Sub
Function EmbeddedLoops(index, k, c, n, arr)
Dim i As Variant
If index >= k Then
PrintArrayOnSingleLine arr
Else
For Each i In c
arr(index) = i
EmbeddedLoops index + 1, k, c, n, arr
Next i
End If
End Function
Public Sub PrintArrayOnSingleLine(myArray As Variant)
Dim counter As Integer
Dim textArray As String
For counter = LBound(myArray) To UBound(myArray)
textArray = textArray & myArray(counter)
Next counter
Debug.Print textArray
End Sub
Sources (Disclaimer - from my blog):
VBA Nested Loop with Recursion
VBA All Combinations

Problem with finding similar numbers in 2 columns in vba

i have problem with my code in vba. I have to find how much similar numbers are in column 1 and 2, but for example Column 1 (6,6,34,21,23,40) and column2 (49,34,6,9,6,20) should write 3 cause there are pairs 6-6, 6-6 and 34-34. I know its messy explenation but i hope its understandable. My code so far is:
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Range("B2:C7").Interior.Color = RGB(135, 134, 125)
Range("B2:B7").Font.ColorIndex = 3
Range("C2:C7").Font.ColorIndex = 5
ileLosowan = 7
Randomize
For i = 2 To ileLosowan
x = Int(Rnd * (49) + 1)
Range("c" & i) = x
Next i
For i = 2 To 7
liczba = Range("c" & i)
For j = 2 To 7
liczbe = Range("b" & j)
If liczbe = liczba Then
Range("c" & i).Interior.Color = RGB(255, 255, 0)
Range("b" & j).Interior.Color = RGB(255, 255, 0)
suma = suma + 1
End If
Next j
Next i
Range("c" & 9) = suma
End Sub
Try this. I invested some time and I added some lines of code. The macro find all the number pairs.
Example (6,6,3,4,2) (2,3,6,9,0) --> results 3: (6-6, 3-3, 2-2)
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Dim str_B As String, str_C As String, str_BC As String
Dim max_rand As Long
ileLosowan = 20 ' you can change the number of element in the column
max_rand = 49 ' max randum number
start_row = 2 'start_row
str_BC = "B2:C" & ileLosowan
str_B = "B2:B" & ileLosowan
str_C = "C2:C" & ileLosowan
Range(str_BC).Interior.Color = RGB(135, 134, 125)
Range(str_B).Font.ColorIndex = 5
Range(str_C).Font.ColorIndex = 5
Randomize
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("C" & i) = x
Next i
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("B" & i) = x
Next i
liczba_array = Range("B" & start_row & ":B" & ileLosowan).Value2
liczbe_array = Range("C" & start_row & ":C" & ileLosowan).Value2
ReDim ID_array(1 To 1)
ID_array(1) = max_rand + 1
Count = 1
For i = 1 To UBound(liczba_array, 1)
For j = 1 To UBound(liczbe_array, 1)
For k = 1 To UBound(ID_array, 1)
If ID_array(k) = j Then
GoTo out
End If
Next k
If liczba_array(i, 1) = liczbe_array(j, 1) Then
Range("B" & (start_row + i - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
Range("C" & (start_row + j - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
suma = suma + 1
ID_array(Count) = j
Count = Count + 1
ReDim Preserve ID_array(1 To Count)
Exit For
End If
Next j
out:
Next i
Range("C" & ileLosowan + 2) = suma
End Sub
Something like this will do what you're after. Just incorporate it into you're code cause I don't really know what's going on there.
Dim i As Long, j As Long, arr As Variant, Total As Integer
For i = 2 To 7 'Rows to loop through in the column
Total = 0
arr = Split(Range("A" & i), ",") 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Range("B" & i), arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
Range("C" & i) = Total 'Write total to another column on same row
Next i
Or if you want a basic function for it that you can use in your sheet you can use this:
Public Function CountMatches(Cell As String, Rng As Range, Optional Delim As String)
Dim i As Long, j As Long, arr As Variant, Total As Integer
If Delim = "" Then Delim = ","
If Rng.Count > 1 Then
CountMatches = "Please choose 1 cell to compare to."
Exit Function
End If
Total = 0
arr = Split(Cell, Delim) 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Rng, arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
CountMatches = Total
End Function
Use it like =CountMatches(A1,B1,",")

Excel VBA: how to apply bold format to all words before ":"?

I am trying to apply the bold format to all words before a colon (:) in a specific cell. In the image, the words first / second / third need to be in bold, the rest not.
I found the following code on a different thread, but it applies the bold format to the first word before a colon.
Sub PreColon()
Dim i As Long, N As Long, s As String, j As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
s = Cells(i, 1)
j = InStr(1, s, ":")
If j <> 0 Then
Cells(i, 1).Characters(1, j - 1).Font.Bold = True
End If
Next i
End Sub
split on the - and do a second loop:
Sub PreColon()
With ActiveSheet
Dim N As Long
N = .Cells(.Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To N
Dim strLen As Long
strLen = 0
Dim sArray() As String
sArray = Split(.Cells(i, 1), "-")
Dim s As Variant
For Each s In sArray
Dim j As Long
j = InStr(s, ":")
If j > 0 Then
.Cells(i, 1).Characters(strLen + 1, j - 1).Font.Bold = True
End If
strLen = strLen + Len(s) + 1
Next s
Next i
End With
End Sub
Here is a little procedure you can use:
Sub Test()
Dim i As Long, N As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
FormatPreColon Cells(i, 1)
Next
End Sub
Sub FormatPreColon(Rng As Range)
Dim i As Long, j As Long
If TypeName(Rng.Value) <> "String" Then Exit Sub
i = InStr(1, Rng, ":")
Do While i <> 0
j = InStrRev(Rng, " ", i) + 1
Rng.Characters(j, i - j).Font.Bold = True
i = InStr(i + 1, Rng, ":")
Loop
End Sub
Possible missing "-" symbol you may use this.
Dim i As Long, s As String, j As Integer, k As Integer, t As String, counter As Integer, N As Integer
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
s = Cells(i, 1)
j = 1
k = 1
Do While j > 0
j = InStr(k, s, ":")
k = j + 1
counter = 1
For m = j - 1 To 1 Step -1
t = Trim(Mid(s, m, 1))
If (t = "" Or m = 1) Then
Cells(i, 1).Characters(m, counter).Font.Bold = True
Exit For
Else
counter = counter + 1
End If
Next m
Loop
DoEvents
Next i
MsgBox "Finito..."

Parsing excel string of numbers using vba

I am trying parse a number string and create rows accordingly. On the left of the Example Data picture is an example of the input data with the right being my desired output. I am wanting to insert a unique row of data for each digit within the brackets for each number combination.
Here is an example of the code I used to try to solve the problem.
Option Explicit
Sub example()
Dim num As Variant
Dim x As Variant
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim m As Integer
Dim test As Variant
Dim test2 As Variant
Dim count As Integer
m = 0
For i = 1 To 3
num = Range("C" & 5 + i + m).Value
For j = 1 To Len(num)
test = Mid(num, j)
If Left(Mid(num, j), 1) = "[" Then
For k = 1 To Len(num) - (j + 1)
m = m + 1
Range("C" & 5 + m + i - 1).EntireRow.Insert
test2 = Left(Mid(num, j + k), 1)
Range("C" & 5 + m + i - 1).Value = Left(num, j - 1) + test2
Next k
End If
Next j
Next i
End Sub
Please consider using the following script:
Sub splitcombinations()
Dim rngCell As Range
Set rngCell = ThisWorkbook.Sheets(1).Range("A2")
Dim strCombinationDigits As String, strBaseDigits As String
Dim intCombinationDigitsLen As Integer
Dim x As Integer
Do While rngCell.Value2 <> ""
If InStr(rngCell.Value2, "[") > 0 Then
strCombinationDigits = Mid(rngCell.Value2, InStr(rngCell.Value2, "[") + 1, InStr(rngCell.Value2, "]") - InStr(rngCell.Value2, "[") - 1)
intCombinationDigitsLen = Len(strCombinationDigits)
strBaseDigits = Left(rngCell.Value2, InStr(rngCell.Value2, "[") - 1)
ActiveSheet.Range(rngCell.Offset(1, 0), rngCell.Offset(intCombinationDigitsLen - 1, 0)).EntireRow.Insert
For x = 1 To intCombinationDigitsLen
rngCell.Offset(x - 1, 0).Value2 = strBaseDigits & Mid(strCombinationDigits, x, 1)
rngCell.Offset(x - 1, 1).Value2 = rngCell.Offset(0, 1).Value2
rngCell.Offset(x - 1, 2).Value2 = rngCell.Offset(0, 2).Value2
Next
End If
Set rngCell = rngCell.Offset(intCombinationDigitsLen , 0)
Loop
End Sub

Separate grouped items in an Excel column

I have a long list of data structured in a column in the following way:
miR-4782-5p
miR-4740-3p
miR-3173-5p
miR-617/2340
miR-1260/1260b/1391
miR-4642
miR-1392
I need to convert it to the following format:
miR-4782-5p
miR-4740-3p
miR-3173-5p
miR-617
miR-2340
miR-1260
miR-1260b
miR-1391
miR-4942
miR-1392
Essentially, I just want to separate the data grouped by parentheses, and make it it's own item while continuing down the list.
Thoughts?
This code should do just what you need
Sub SplitCellsAndExtend_Olddasgf()
'takes cells with inside line feeds and creates new row for each.
'reverses merge into top cell.
Dim strCell As String, lastRow As Long, i As Long, j As Long, sPrefix As String
Const sSplitOn As String = "/"
application.ScreenUpdating = False
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = lastRow To 1 Step -1
strCell = Cells(i, 1)
j = 0
Do While InStr(1, strCell, sSplitOn) > 0
Rows(i + j + 1).Insert
sPrefix = Left(strCell, InStr(strCell, "-"))
strCell = Right(strCell, Len(strCell) - InStr(1, strCell, sSplitOn))
Cells(i + j, 1) = Left(Cells(i + j, 1).Value, InStr(1, Cells(i + j, 1), sSplitOn) - 1)
strCell = sPrefix & strCell
Cells(i + j + 1, 1).Value = strCell
j = j + 1
Loop
Next
application.ScreenUpdating = True
End Sub

Resources