VBA Adding Custom Object in Collection to Temp Variable - excel

So I've followed some examples Ive seen on sorting items in a collection, but for some reason when I try to store an element I a temporary variable I get a warning from vba "Object doesn't support this property or method", I set the temp variable to variant but it doesn't seem to care. Could it be an issue with my object type?
Sub selectRange()
Dim lastrow As Long
Dim lastColumn As Long
Dim j As Integer
Dim i As Integer
Dim streamColl As Collection
Dim ws As Worksheet
Dim rowCount As Integer
Dim columnCount As Integer
Dim tempStream As Stream
Set ws = ActiveWorkbook.Sheets("Sheet1")
Range("E5").Select
lastrow = Range("E5", ActiveCell.End(xlDown)).Count + 5
lastColumn = Range("E5", ActiveCell.End(xlToRight)).Count
Set streamColl = New Collection
For i = 1 To lastColumn
Set tempStream = New Stream
tempStream.StreamName = Cells(3, i + 4).value
tempStream.Temperature = Cells(5, i + 4).value
tempStream.Pressure = Cells(6, i + 4).value
tempStream.VapGasFlow = Cells(7, i + 4).value
tempStream.VapMW = Cells(8, i + 4).value
tempStream.VapZFactor = Cells(9, i + 4).value
tempStream.VapViscosity = Cells(10, i + 4).value
tempStream.LightLiqVolFlow = Cells(11, i + 4).value
tempStream.LightLiqMassDensity = Cells(12, i + 4).value
tempStream.LightLiqViscosity = Cells(13, i + 4).value
tempStream.HeavyLiqVolFlow = Cells(14, i + 4).value
tempStream.HeavyLiqMassDensity = Cells(15, i + 4).value
tempStream.HeavyLiqViscosity = Cells(16, i + 4).value
streamColl.Add tempStream
Next
MsgBox streamColl(1).StreamName
Call sortStream(streamColl)
End Sub
Sub sortStream(ByVal pStreamColl As Collection)
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim lastColumn As Integer
Dim vTemp as variant
lastColumn = 0
k = 1
Do While IsNumeric(pStreamColl(k).StreamName)
lastColumn = lastColumn + 1
k = k + 1
Loop
MsgBox lastColumn
For i = 1 To lastColumn
For j = i + 1 To lastColumn
If pStreamColl(j).StreamName < pStreamColl(i).StreamName Then
vTemp = pStreamColl(j)
pStreamColl.Remove j
pStreamColl.Add vTemp, vTemp, i
End If
Next j
Next i
For Each Stream In pStreamColl
Debug.Print Stream.StreamName
Next Stream
End sub
the error gets thrown on the line
vtemp = pStreamColl(j)
Would using an array be better?

Stream()
You could use an Array of Streams
ReDim Streams(1 To lastColumn) As New Stream
For i = 1 To lastColumn
With Streams(i)
.StreamName = Cells(3, i + 4).Value
.Temperature = Cells(5, i + 4).Value
.Pressure = Cells(6, i + 4).Value
.VapGasFlow = Cells(7, i + 4).Value
.VapMW = Cells(8, i + 4).Value
.VapZFactor = Cells(9, i + 4).Value
.VapViscosity = Cells(10, i + 4).Value
.LightLiqVolFlow = Cells(11, i + 4).Value
.LightLiqMassDensity = Cells(12, i + 4).Value
.LightLiqViscosity = Cells(13, i + 4).Value
.HeavyLiqVolFlow = Cells(14, i + 4).Value
.HeavyLiqMassDensity = Cells(15, i + 4).Value
.HeavyLiqViscosity = Cells(16, i + 4).Value
End With
Next
Use StrComp to sort Strings
Function StrComp(String1, String2, [Compare As VbCompareMethod = vbBinaryCompare])
Reference: How to use the STRCOMP Function (VBA)
Sub sortStream(ByRef Streams() As Stream)
Dim swapped As Boolean, st As Stream
Dim n As Long
Do
swapped = False
For n = LBound(Streams) + 1 To UBound(Streams)
If StrComp(Streams(n - 1).StreamName, Streams(n).StreamName, vbTextCompare) = 1 Then
Set st = Streams(n - 1)
Set Streams(n - 1) = Streams(n)
Set Streams(n) = st
swapped = True
End If
Next
Loop Until Not swapped
End Sub
I only suggested the Stream() because I wanted to write a Bubble Sort. I would use a SortedList.
SortedList
MSDN SortedList
Represents a collection of key/value pairs that are sorted by the keys and are accessible by key and by index.
Additional Reference:VBA SortedList
You will need to make these changes to use a SortedList:
Before
Dim streamColl As Collection
Set streamColl = New Collection
streamColl.Add tempStream
After
Dim streamColl As Object
Set streamColl = CreateObject("System.Collections.SortedList")
streamColl.Add Key:=tempStream.StreamName, Value:=tempStream.

Related

Type mismatch error for worksheet object in VBA, how can i solve?

'Private Sub CommandButton1_Click()
Dim MySheetu As String, ws As Worksheet
MySheetu = operationplan.Value
Set ws = Worksheets(MySheetu)
Dim a As Variant
Dim b As Long
Dim c As Variant
Dim d As Variant
Dim e As Variant
Dim str1 As String
Dim str2 As String
Dim lastrow As Long
Dim lastcol As Long
Dim lastrow2 As Long
Dim lastrow3 As Long
Dim i As Variant
Dim j As Variant
Dim k As Variant
Dim dsheet As Worksheet
lastrow = Worksheets(1).Cells(Rows.Count, 21).End(xlUp).Row
For a = 2 To lastrow
ws.Cells((a), 1).Value = Worksheets(1).Cells(a, 21).Value
ws.Cells((a), 2).Value = Worksheets(1).Cells(a, 22).Value
ws.Cells((a), 3).Value = Worksheets(1).Cells(a, 23).Value
ws.Cells((a), 4).Value = Worksheets(1).Cells(a, 20).Value
ws.Cells((a), 5).Value = Worksheets(1).Cells(a, 26).Value
ws.Cells((a), 6).Value = Worksheets(1).Cells(a, 1).Value
ws.Cells((a), 7).Value = Worksheets(1).Cells(a, 1).Value
Next a
ws.Cells(1, 1).Value = "operasyon"
ws.Cells(1, 2).Value = "öncelik"
ws.Cells(1, 3).Value = "ardillik"
ws.Cells(1, 4).Value = "operasyon süresi"
ws.Cells(1, 5).Value = "sabit istasyon"
ws.Cells(1, 6).Value = "distinct_istasyon"
ws.Cells(1, 7).Value = "istasyon"
Columns(6).RemoveDuplicates Columns:=Array(1)
For b = lastrow To 1 Step -1
If Cells(b, 1).Text = "#N/A" Then
Rows(b).Delete
End If
Next b
lastrow2 = ws.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastrow2
For j = 2 To lastrow2
If ws.Cells(i, 1).Value = ws.Cells(j, 2).Value Then
ws.Cells((j), 2) = i - 1
End If
Next j
Next i'
I got mismatch error in "If ws.Cells(i, 1).Value = ws.Cells(j, 2).Value Then" line how can i solve this error? I add additional codes below them. İ try cstr function but it cant work? Could you please help with these additional codes. The error is in the same line and it use user form text box value to refer the sheet

Select the First and Last Values in a Subset of String Values

VBA Code:
Sub Example():
Dim i As Double
Dim Letter As String
Dim var1 As Long
Dim var2 As Long
Dim Row_For_Table As Integer
Row_For_Table = 1
For i = 1 To 12
If Cells(i + 1, 1).Value <> Cells(i, 1).Value Then
'MsgBox ("different")
Letter = Cells(i, 1).Value
var2 = Cells(i, 3).Value
var1 = Cells(i, 2).Value
Range("F" & Row_For_Table).Value = Letter
Range("G" & Row_For_Table).Value = var2 - var1
Row_For_Table = Row_For_Table + 1
Else
'MsgBox ("same")
End If
Next i
End Sub
I would like to create summary table of A, B, and C with the Values of (14-1), (12-5), and (4-1). I would like to write this is VBA as a template for a bigger project.
Thank you.
This uses a dictionary to do what you are looking for. It assumes your table is sorted by Column A.
Dim i As Long
Dim lr As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
With Sheets("Sheet1") 'Change as needed
lr = .Cells(.Rows.Count, 1).End(xlUp).Row 'Lastrow
For i = 1 To lr + 1
If Not dict.exists(.Cells(i, 1).Value) Then 'Key doesn't exist
dict.Add .Cells(i, 1).Value, .Cells(i, 2).Value 'Add key and first value
If i > 1 Then 'Avoid out of range errors
dict(.Cells(i - 1, 1).Value) = .Cells(i - 1, 3).Value - dict(.Cells(i - 1, 1).Value) 'Subtract old value from new value
End If
End If
Next i
Dim key As Variant
i = 1
For Each key In dict
.Cells(i, 6).Value = key 'place values
.Cells(i, 7).Value = dict(key)
i = i + 1
Next key
End With
This also uses a dictionary and should work for multiple columns.
Option Explicit
Sub StuffDo()
Dim rng As Range
Dim arrData As Variant
Dim ky As Variant
Dim dicLetters As Object
Dim arrNumbers()
Dim cnt As Long
Dim idxCol As Long
Dim idxRow As Long
arrData = Sheets("Sheet1").Range("A1").CurrentRegion.Value
Set dicLetters = CreateObject("Scripting.Dictionary")
For idxRow = LBound(arrData, 1) To UBound(arrData, 1)
For idxCol = LBound(arrData, 2) + 1 To UBound(arrData, 2)
ky = arrData(idxRow, 1)
If Not dicLetters.exists(ky) Then
arrNumbers = Array(arrData(idxRow, idxCol))
Else
arrNumbers = dicLetters(ky)
cnt = UBound(arrNumbers) + 1
ReDim Preserve arrNumbers(cnt)
arrNumbers(cnt) = arrData(idxRow, idxCol)
End If
dicLetters(ky) = arrNumbers
Next idxCol
Next idxRow
Set rng = Range("A1").Offset(, Range("A1").CurrentRegion.Columns.Count + 2)
For Each ky In dicLetters.keys
arrNumbers = dicLetters(ky)
rng.Value = ky
rng.Offset(, 1) = arrNumbers(UBound(arrNumbers))
rng.Offset(, 2) = arrNumbers(0)
Set rng = rng.Offset(1)
Next ky
End Sub

VBA For Loop populating last entry until end

first post and also new to VBA so I apologize for anything that is unclear. I have created a code to generate a daily printout of employees, equipment, and subcontractors. The loop is looking for "S" (subcontractors) each day. There is only one day where "S" is present and there are 4 on that day. The issue is that the loop begins correctly and populates the correct information when it finds "S" and lists the 4 separate subcontractors, but every day before and after that it continues to list the first subcontractor even though no "S" is found on those dates. How can I get it to clear that entry if no other "S" are found? I hope that makes sense and I have included the code. Thank you!
Screesnhot
Sub WriteReport_Click()
Dim EachName(1 To 5000) As Variant
Dim NameHours(1 To 5000) As Variant
Dim NamePhase(1 To 5000) As Variant
Dim EquipHours(1 To 5000) As Variant
Dim EquipPhase(1 To 5000) As Variant
Dim EachDate(1 To 5000) As Date
Dim EachEquip(1 To 5000) As Variant
Dim EachSub(1 To 5000) As Variant
Dim SubAmount(1 To 5000) As Variant
Dim i As Long 'loop through records
Dim k As Integer 'count employees
Dim h As Integer 'count equipment
Dim t As Integer 'count subcontractor
Dim m As Integer 'count dates
Dim j As Integer
Dim x As Integer
Dim lr, s, p, StartBorder, EndBorder As Integer 'keeps row counts Start & Finish
Dim TestString As String
Sheets("Data").Activate
k = 1 'counts EachName
h = 1 'counts EachEquip
t = 1 'counts EachSub
m = 1 'counts dates
lr = 1
p = 0
For i = 1 To Rows.Count
If Cells(i, 3) = "L" Then
EachName(1) = Cells(i, 11)
Exit For
End If
Next i
For i = 1 To Rows.Count
If Cells(i, 3) = "E" Then
EachEquip(1) = Cells(i, 12)
Exit For
End If
Next i
For i = 1 To Rows.Count
If Cells(i, 3) = "S" Then
EachSub(1) = Cells(i, 9)
Exit For
End If
Next i
NameHours(1) = 0
EquipHours(1) = 0
EachDate(1) = Cells(1, 1)
SubAmount(1) = 0
Dim LastRow As Integer
For i = 1 To 5000
If EachDate(m) <> Cells(i, 1) Then
m = m + 1 'setting array for next new date
EachDate(m) = Cells(i, 1)
lr = Sheets("Report").Cells(Rows.Count, 1).End(xlUp).Row + 1
StartBorder = lr
Sheets("Report").Cells(lr, 1) = Format(EachDate(m - 1), "mm/dd/yy") 'prints date
Sheets("Report").Cells(lr, 1).Interior.ColorIndex = 4 'highlights date
For j = 1 To k 'prints employees, hours and phase
Sheets("Report").Cells((lr + j), 1) = EachName(j)
Sheets("Report").Cells((lr + j), 2) = NameHours(j)
Sheets("Report").Cells((lr + j), 4) = NamePhase(j)
Sheets("Report").Cells((lr + j), 5).Formula = _
"=IF(A" & CStr(lr + j) & "<>"""",VLOOKUP(A" & CStr(lr + j) & ",Employee,2,FALSE),"""")"
Next j
k = 1
lr = Sheets("Report").Cells(Rows.Count, 1).End(xlUp).Row + 1
For s = i To 5000 'getting first employee for next date
If Cells(s, 1) = EachDate(m) And Cells(s, 3) = "L" Then
EachName(1) = Cells(s, 11)
Exit For
End If
Next s
Erase NameHours 'clearing manhours for next date
For j = 1 To h
Sheets("Report").Cells((lr + j), 1) = Trim(EachEquip(j))
Sheets("Report").Cells((lr + j), 3) = EquipHours(j)
Sheets("Report").Cells((lr + j), 4) = EquipPhase(j)
Sheets("Report").Cells((lr + j), 5).Formula = _
"=LEFT(IF(A" & CStr(lr + j) & "<>"""",VLOOKUP(A" & CStr(lr + j) & ",EquipList,2,FALSE),""""),20)"
Next j
h = 1
For s = i To 5000 'getting first equipment for next date
If Cells(s, 1) = EachDate(m) And Cells(s, 3) = "E" Then
EachEquip(1) = Cells(s, 12)
Exit For
End If
Next s
Erase EquipHours ' clearing equipment hours for next date
lr = Sheets("Report").Cells(Rows.Count, 1).End(xlUp).Row + 1
For x = 1 To t
Sheets("Report").Cells((lr + x), 1) = EachSub(x)
Sheets("Report").Cells((lr + x), 3) = SubAmount(x)
Next x
For x = i To 5000 'getting subcontractor for next date
If Cells(x, 1) = EachSub(m) And Cells(x, 3) = "S" Then
EachSub(1) = " "
Exit For
End If
Next x
EndBorder = lr + x
t = 1
With Worksheets("Report") 'draws borders
.Range(.Cells(StartBorder, 1), .Cells(EndBorder, 8)).BorderAround ColorIndex:=1, Weight:=xlThick
End With
End If
Select Case Cells(i, 3).Value
Case "L"
If Cells(i, 11) = EachName(k) Then
If Cells(i, 7) = 0 Then
p = p + 1 'adding up per diem
End If
NamePhase(k) = Cells(i, 2)
NameHours(k) = NameHours(k) + Cells(i, 7)
Else
k = k + 1
EachName(k) = Cells(i, 11)
NamePhase(k) = Cells(i, 2)
If Cells(i, 7) = 0 Then
p = p + 1
End If
NameHours(k) = NameHours(k) + Cells(i, 7)
End If
Case "E"
If Cells(i, 12) = EachEquip(h) Then
EquipPhase(h) = Cells(i, 2)
EquipHours(h) = EquipHours(h) + Cells(i, 7)
Else
h = h + 1
EachEquip(h) = Cells(i, 12)
EquipPhase(h) = Cells(i, 2)
EquipHours(h) = EquipHours(h) + Cells(i, 7)
End If
Case "S"
If Cells(i, 9) = EachSub(t) Then
EachSub(t) = Cells(i, 9)
SubAmount(t) = SubAmount(t) + Cells(i, 8)
Else
t = t + 1
EachSub(t) = Cells(i, 9)
SubAmount(t) = SubAmount(t) + Cells(i, 8)
End If
End Select
Next i
MsgBox "Report Completed !!!"
End Sub
You will find your code easier to debug/maintain if you separate the collection of the data and the report generation into 2 discrete steps, preferably in subroutines. For example
Option Explicit
Dim EachName(0 To 5000, 1 To 3) As Variant '1=name 2=hours 3=phase
Dim EachEquip(0 To 5000, 1 To 3) As Variant '1=name 2=hrs 3=phase
Dim EachSub(0 To 5000, 1 To 2) As Variant ' 1=name 2=amount
Dim k As Long 'count employees
Dim h As Long 'count equipment
Dim t As Long 'count subcontractor
Sub WriteReport_Click()
' specify book and sheets to process
Dim wb As Workbook, wsData As Worksheet, wsRep As Worksheet
Set wb = ThisWorkbook ' or ActiveWorkBook
' determine extent of data
Dim LastRow As Long, iRow As Long
Set wsData = wb.Sheets("Data")
LastRow = wsData.Cells(Rows.Count, 1).End(xlUp).Row
' clear report sheet
Set wsRep = wb.Sheets("Report")
wsRep.Cells.Clear
' scan data for first date
Dim RepDate As Date
RepDate = wsData.Cells(1, 1)
Call GetData(RepDate, wsData)
' scan data for more dates
For iRow = 1 To LastRow
If wsData.Cells(iRow, 1) <> RepDate Then
' report existing date
Call ReportData(RepDate, wsRep)
' get data for new date
RepDate = wsData.Cells(iRow, 1)
Call GetData(RepDate, wsData)
End If
Next
' report last date
Call ReportData(RepDate, wsRep)
'end
wsRep.Columns("A:E").AutoFit
MsgBox "Report Completed", vbInformation, LastRow & " rows scanned"
End Sub
Sub ReportData(d As Date, ws As Worksheet)
Debug.Print "ReportData", d
Dim lr As Long, StartBorder As Long, EndBorder As Long, j As Long
lr = ws.Cells(Rows.Count, 1).End(xlUp).Row + 1
StartBorder = lr
ws.Cells(lr, 1) = Format(d, "mm/dd/yy") 'prints date
ws.Cells(lr, 1).Interior.ColorIndex = 4 'highlights date
'prints employees, hours and phase
For j = 1 To k
ws.Cells((lr + j), 1) = EachName(j, 1) 'empoyee name
ws.Cells((lr + j), 2) = EachName(j, 2) 'hrs
ws.Cells((lr + j), 4) = EachName(j, 3) 'phase
ws.Cells((lr + j), 5).Formula = _
"=IF(A" & CStr(lr + j) & "<>"""",VLOOKUP(A" & CStr(lr + j) & ",Employee,2,FALSE),"""")"
Next j
' report equipment
lr = ws.Cells(Rows.Count, 1).End(xlUp).Row + 1
For j = 1 To h
ws.Cells((lr + j), 1) = EachEquip(j, 1) 'equip name
ws.Cells((lr + j), 3) = EachEquip(j, 2) 'hours
ws.Cells((lr + j), 4) = EachEquip(j, 3) 'phase
ws.Cells((lr + j), 5).Formula = _
"=LEFT(IF(A" & CStr(lr + j) & "<>"""",VLOOKUP(A" & CStr(lr + j) & ",EquipList,2,FALSE),""""),20)"
Next j
' report sub contractors
lr = ws.Cells(Rows.Count, 1).End(xlUp).Row + 1
For j = 1 To t
ws.Cells((lr + j), 1) = EachSub(j, 1) 'sub name
ws.Cells((lr + j), 3) = EachSub(j, 2) 'amount
Next j
' draws borders
EndBorder = ws.Cells(Rows.Count, 1).End(xlUp).Row
ws.Range(ws.Cells(StartBorder, 1), ws.Cells(EndBorder, 8)) _
.BorderAround ColorIndex:=1, Weight:=xlThick
End Sub
Sub GetData(d As Date, ws As Worksheet)
Debug.Print "GetData", d
Dim LastRow As Long, i As Long
LastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
' clear global arrays
Erase EachName
Erase EachEquip
Erase EachSub
k = 0: h = 0: t = 0
For i = 1 To LastRow
If ws.Cells(i, 1) = d Then
Select Case ws.Cells(i, 3)
Case "L" ' Employee
If ws.Cells(i, 11) <> EachName(k, 1) Then
k = k + 1
End If
EachName(k, 1) = ws.Cells(i, 11)
EachName(k, 2) = ws.Cells(i, 7) + EachName(k, 2) ' hours
EachName(k, 3) = ws.Cells(i, 2) ' phase
Case "E" ' Equipment
If ws.Cells(i, 12) <> EachEquip(h, 1) Then
h = h + 1
End If
EachEquip(h, 1) = Trim(ws.Cells(i, 12)) ' equip name
EachEquip(h, 2) = ws.Cells(i, 7) + EachEquip(h, 2) ' hours
EachEquip(h, 3) = ws.Cells(i, 2) ' phase
Case "S" ' Subcontractor
If ws.Cells(i, 9) <> EachSub(t, 1) Then
t = t + 1
End If
EachSub(t, 1) = ws.Cells(i, 9) ' sub name
EachSub(t, 2) = ws.Cells(i, 8) + EachSub(t, 2) ' amount
Case Else
MsgBox "Unknown code at row " & i, vbExclamation
End Select
End If
Next
End Sub

How can I optimize vba code for combination of numbers

I am working on a problem to find combinations equal to 100 with different vector length as input. The code is working fine for the small sequence but code takes a lot of time when the sequence of numbers increases. I need to reduce the time as much as I can because sometimes it takes an hour. The maximum value of vector length can be 6 & minimum increment can be 5 so the maximum we can get is 36 numbers and output of their combinations in a set of 6. Any help in the optimization of code to a minimum possible time would be great.
Here is the snap of sheet:
Here is the code:
Sub Combinations()
Dim rRng As Range, p As Integer
Dim vElements, lrow As Long, vresult As Variant
Range("A2:A100").Clear
Call Sequence
lrow = 25
Set rRng = Range("A2", Range("A2").End(xlDown)) ' The set of numbers
p = Range("C2").Value ' How many are picked
vElements = Application.Index(Application.Transpose(rRng), 1, 0)
ReDim vresult(1 To p)
Columns("E").Resize(, p + 5).Clear
Call CombinationsNP(vElements, p, vresult, lrow, 1, 1)
Call Delrow
Call formu
Range("C27:D15000").Clear
End Sub
Sub CombinationsNP(vElements As Variant, p As Integer, vresult As Variant, lrow As Long, iElement As Integer, iIndex As Integer)
Dim i As Integer
For i = iElement To UBound(vElements)
vresult(iIndex) = vElements(i)
If iIndex = p Then
lrow = lrow + 1
Range("E" & lrow + 1).Resize(, p) = vresult
Else
Call CombinationsNP(vElements, p, vresult, lrow, i + 1, iIndex + 1)
End If
Next i
End Sub
Sub Delrow()
Dim lrow As Long
Dim i As Long
Dim x As Integer
lrow = Cells(Rows.Count, 5).End(xlUp).Row
For i = 27 To lrow + 1
x = Cells(i, 5).Value + Cells(i, 6).Value + Cells(i, 7).Value + Cells(i, 8).Value + Cells(i, 9).Value + Cells(i, 10).Value
If x <> 100 And Cells(i, 5).Value <> "" Then
Cells(i, 5).EntireRow.Delete
i = i - 1
End If
Next i
End Sub
Sub Sequence()
Dim i As Integer
Dim x As Integer
Dim y As Integer
Dim a As Integer
Dim b As Integer
b = Cells(2, 3).Value
For i = 2 To Cells(2, 3).Value - 1
Cells(i, 1).Value = 0
Next i
For y = 0 To 100 Step Cells(8, 3).Value
a = 1
If y <> 0 Then
a = Int(100 / y)
If a > b Then
a = b
End If
End If
For x = 1 To a
Cells(i, 1).Value = y
i = i + 1
Next x
Next y
End Sub
Sub formu()
Dim lastrow As Long
lastrow = Cells(Rows.Count, 5).End(xlUp).Row
Range("D27:D" & lastrow).formula = "=E27&F27&G27&H27&I27&J27"
Range("C27:C" & lastrow).formula = "=IF(COUNTIF($D$27:$D$150000,D27)=1,FALSE,NOT(COUNTIF($D$2:D27,D27)=1))"
Range("$C$26:$C$150000").AutoFilter Field:=1, Criteria1:="TRUE"
Range("C27:C150000").EntireRow.Delete
Sheet5.ShowAllData
End Sub
I think this code is slow because of how often it touches the worksheet. There are both read and writes to worksheets in loops. There is also a recursive function that writes to the worksheet in a loop. I can't tell if you are doing this for ease of use or because you need to display the output. Avoid writing to the worksheet until output is required. Output all the data at once, instead of one cell at a time. See the example I give in the Sequence procedure.
I made the code have fully defined references so the system has to do less guessing and lookups. I doubt the performance change will be drastic.
Option Explicit
Public Sub Combinations()
Dim rRng As Range
Dim p As Long
Dim vElements As Variant
Dim lrow As Long
ActiveSheet.Range("A2:A100").Clear
Sequence
lrow = 25
Set rRng = ActiveSheet.Range("A2", ActiveSheet.Range("A2").End(xlDown)) ' The set of numbers
p = ActiveSheet.Range("C2").Value ' How many are picked
vElements = Application.WorksheetFunction.Index(Application.WorksheetFunction.Transpose(rRng), 1, 0)
ReDim vresult(1 To p)
ActiveSheet.Columns("E").Resize(, p + 5).Clear
CombinationsNP vElements, p, vresult, lrow, 1, 1
Delrow
formu
ActiveSheet.Range("C27:D15000").Clear
End Sub
Public Sub CombinationsNP(vElements As Variant, p As Long, vresult As Variant, lrow As Long, ByVal iElement As Long, iIndex As Long)
Dim i As Long
For i = iElement To UBound(vElements)
vresult(iIndex) = vElements(i)
If iIndex = p Then
lrow = lrow + 1
ActiveSheet.Range("E" & lrow + 1).Resize(, p) = vresult
Else
CombinationsNP vElements, p, vresult, lrow, i + 1, iIndex + 1
End If
Next i
End Sub
Public Sub Delrow()
Dim lrow As Long
Dim i As Long
Dim x As Long
With ActiveSheet
lrow = .Cells(.Rows.Count, 5).End(xlUp).Row
For i = 27 To lrow + 1
x = .Cells(i, 5).Value + .Cells(i, 6).Value + .Cells(i, 7).Value + .Cells(i, 8).Value + .Cells(i, 9).Value + .Cells(i, 10).Value
If x <> 100 And .Cells(i, 5).Value <> vbNullString Then
.Cells(i, 5).EntireRow.Delete
i = i - 1
End If
Next i
End With
End Sub
Public Sub Sequence()
Dim i As Long
Dim x As Long
Dim y As Long
Dim a As Long
Dim b As Long
' Example of setting all the cells at once
With ActiveSheet
b = .Cells(2, 3).Value
.Range(.Cells(2, 1), .Cells(b - 1, 1)).Value = 0
End With
For y = 0 To 100 Step ActiveSheet.Cells(8, 3).Value
a = 1
If y <> 0 Then
a = Int(100 / y)
If a > b Then
a = b
End If
End If
For x = 1 To a
ActiveSheet.Cells(i, 1).Value = y
i = i + 1
Next x
Next y
End Sub
Public Sub formu()
Dim lastrow As Long
With ActiveSheet
lastrow = .Cells(.Rows.Count, 5).End(xlUp).Row
.Range("D27:D" & lastrow).Formula = "=E27&F27&G27&H27&I27&J27"
.Range("C27:C" & lastrow).Formula = "=IF(COUNTIF($D$27:$D$150000,D27)=1,FALSE,NOT(COUNTIF($D$2:D27,D27)=1))"
.Range("$C$26:$C$150000").AutoFilter Field:=1, Criteria1:="TRUE"
.Range("C27:C150000").EntireRow.Delete
End With
Sheet5.ShowAllData
End Sub

How to split strings based on special character (multiple times)

I'm trying to split a string based on ampersand (&), remove all the ampersands and separate each part to columns.
The number of strings differ every time.
Sample text:
My output:
What I need:
For i = 2 To 7
fullname = Cells(i, 1).Value
commaposition = InStr(fullname, "&")
Cells(i, 2).Value = Left(fullname, commaposition - 2)
For x = 2 To 7
fullname = Cells(i, 1).Value
commaposition = InStr(fullname, "&")
Cells(i, 3).Value = Mid(fullname, commaposition + 2)
Cells(x, 3).Value = Mid(fullname, commaposition + 2)
For y = 2 To 7
fullname = Cells(i, 1).Value
commaposition = InStr(fullname, "&")
Cells(i, 4).Value = Mid(fullname, commaposition + 2)
Cells(x, 4).Value = Mid(fullname, commaposition + 2)
Next y
Next x
Next i
Another option (other then #Storax's method) would be to use Regular Expressions which could account for more then just an ampersand.
Option Explicit
Public Sub FindNames()
Dim rng As Range
Dim j As Long
Dim c, Match
' Update for your range
With ActiveSheet
Set rng = .Range(.Cells(1, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1))
End With
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "\w+"
For Each c In rng
j = 0
If .test(c.Value2) Then
For Each Match In .Execute(c.Value2)
j = j + 1
c.Offset(0, j).Value2 = Match
Next Match
End If
Next c
End With
End Sub
You could try something like that
Sub SplitAmper()
Const AP = "&"
Dim v As Variant
Dim rg As Range
Set rg = Range("A2:A7") ' Adjust to your needs
Dim sngCell As Range
For Each sngCell In rg
v = Split(sngCell.Value, AP)
Cells(sngCell.Row, 1).Resize(, UBound(v) + 1) = v
Next
End Sub
Update: Another solution mentioned in the comments from SJR would be Text to Columns
Sub AnotherAmper()
Const AP = "&"
Dim rg As Range
Set rg = Range("A1:A7") ' Adjust to your needs
rg.TextToColumns Destination:=Range("B1"), DataType:=xlDelimited, _
Other:=True, OtherChar:=AP
End Sub

Resources