How to output assigned values in VBA - vba

could someone please help me with this pretty simple problem I am having. Basically this is a simplified code for more a more complex problem I am trying to solve. I want to be able to output the values I have assigned to a,b,c,d and e in the column b. The values I have used for a,b,c,d and e are taken from cells a1,a2,a3,a4 and a5.
Thanks :)
Sub help()
Dim letters As String
Dim count As Integer
a = Range("a1").Value
b = Range("a2").Value
c = Range("a3").Value
d = Range("a2").Value
e = Range("a3").Value
letters = "abcde"
For count = 1 To Len(letters)
Range("b" & count) = Mid(letters, count, 1)
Next
'HOW DO I OUTPUT THE ASSIGNED VALUES TO a,b,c,d & e RATHER THAN OUTPUTTING LETTERS?'
End Sub

The easiest way is to change your code as follows:
Sub help()
a = Range("a1").Value
b = Range("a2").Value
c = Range("a3").Value
d = Range("a2").Value
e = Range("a3").Value
Range("b1").Value = a
Range("b2").Value = b
Range("b3").Value = c
Range("b4").Value = d
Range("b5").Value = e
End Sub
Alternatively, you could use an array instead of individual variables, e.g.
Sub help()
Dim myArr(1 To 5) As Variant
Dim count As Long
For count = 1 To 5
myArr(count) = Cells(count, "A").Value
Next count
For count = 1 To 5
Cells(count, "B").Value = myArr(count)
Next count
End Sub
That could also be simplified by saying:
Sub help()
Dim myArr As Variant
myArr = Range("A1:A5").Value ' myArr will be a two-dimensional array
Range("B1:B5").Value = myArr
End Sub
Or, as John Coleman suggested in a comment, you could use a Dictionary:
Sub help()
Dim myVars As Object
Dim letters As String
Dim count As Long
Set myVars = CreateObject("Scripting.Dictionary")
myVars("a") = Range("a1").Value
myVars("b") = Range("a2").Value
myVars("c") = Range("a3").Value
myVars("d") = Range("a2").Value
myVars("e") = Range("a3").Value
letters = "abcde"
For count = 1 To Len(letters)
Range("b" & count) = myVars(Mid(letters, count, 1))
Next
End Sub

Simply turn around the assignment you made to the variable and make it go to the cell.
A couple other quick tips:
Also, while VBA doesn't require specific variable declarations, the implicit declared type is always Variant. So it's considered professional practice to declare all variables and always use Option Explicit.
Always define and set references to the workbook and worksheets.
So...
Sub help()
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Dim a as String
a = ws.Range("A1")
ws.Range("B1") = a
End Sub

Related

Format cells with the same values split by a delimiter, but a different order in VBA

I am a VBA beginner, who cannot seem to find a solution to what seemed to be a very easy comparison to me at first.
Basically, I have 2 columns where the values in the cells are split by a delimiter, however, not in the same order.
eg.
Range("A1").value = "1234|5678"
Range("B1").value = "5678|1234"
B1 should then be highlighted as a duplicate
I am searching for some vba code which I can use to loop through the used range's in Columns A & B, to compare and highlight cells in column B that are duplicated, as per example above.
Apologies if I missed any similar questions asked and answered previously, I have indeed conducted a search but perhaps my search criteria may have been out of bounds, and I simply did not come across the VBA solution.
Regards,
Enjay
Based on the little information given you could try the following code
Sub Highlight()
Const DELIMITER = "|"
Dim rg As Range
Dim a As Variant
Dim b As Variant
Dim sngCell As Range
Set rg = Range("A1:A3")
For Each sngCell In rg
a = Split(sngCell.Value2, DELIMITER)
b = Split(sngCell.Offset(, 1).Value2, DELIMITER)
If isEqual(a, b) Then
With sngCell.Offset(, 1).Interior
.ThemeColor = xlThemeColorAccent6
End With
End If
Next sngCell
End Sub
with the following functions
Function isEqual(a As Variant, b As Variant) As Boolean
a = BubbleSort(a)
b = BubbleSort(b)
isEqual = True
Dim i As Long
For i = LBound(a) To UBound(a)
If a(i) <> b(i) Then
isEqual = False
Exit For
End If
Next i
End Function
Function BubbleSort(ByRef strArray As Variant) As Variant
'sortieren von String Array
'eindimensionale Array
'Bubble-Sortier-Verfahren
Dim z As Long
Dim i As Long
Dim strWert As Variant
For z = UBound(strArray) - 1 To LBound(strArray) Step -1
For i = LBound(strArray) To z
If LCase(strArray(i)) > LCase(strArray(i + 1)) Then
strWert = strArray(i)
strArray(i) = strArray(i + 1)
strArray(i + 1) = strWert
End If
Next i
Next z
BubbleSort = strArray
End Function
This will answer your question as-is. If the solution needs to be adjusted, I trust that you can fix it :)
This uses StrComp to (in memory only) re-order the two string parts so that it can easily detect duplicate values.
Option Explicit
Sub DuplicateCheck()
Dim delimiter As String
delimiter = "|"
Dim lastCol As Long
lastCol = Cells(1, Columns.count).End(xlToLeft).Column
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To lastCol
Dim theSplit As Variant
theSplit = Split(Cells(1, i), delimiter)
Dim temp As String
If StrComp(theSplit(0), theSplit(1), vbTextCompare) = 1 Then
temp = theSplit(1)
theSplit(1) = theSplit(0)
theSplit(0) = temp
End If
temp = theSplit(0) & delimiter & theSplit(1)
If Not dict.exists(temp) Then
dict.Add (temp), 1
Else
Cells(1, i).Interior.color = 65535
End If
Next i
End Sub

Using VBA to copy a (fixed range) iterated column in Sheet1 to a range of columns in Sheet2

I have a range of numbers in Sheet1 (AG6:AG25) that contain the RAND() function, and I'm looking to iterate the outcomes for each via pasting transposed values into Sheet2 on a new row for each iteration.
Solved as follows:
Sub MonteCarlo()
Dim transposedVariant As Variant
Dim sourceRowRange As Range
Dim sourceRowRangeVariant As Variant
Dim rangeFilledWithTransposedData As Range
Dim i As Long
Application.ScreenUpdating = False
For i = 1 To 5000
Set sourceRowRange = Sheets("Sheet1").Range("AG6:AG25")
sourceRowRangeVariant = sourceRowRange.Value
transposedVariant = Application.Transpose(sourceRowRangeVariant)
Set rangeFilledWithTransposedData = Sheets("Sheet2").Range("A" & i & ":T" & i)
rangeFilledWithTransposedData.Value = transposedVariant
Next i
Application.ScreenUpdating = True
End Sub
Please find the code. I hope it will help you.
Sub simulation()
Dim i As Long
Dim j As Long
For i = 1 To 1000
For j = 1 To 20
'Calculate
Sheet1.Cells(j, 1) = Application.WorksheetFunction.RandBetween(100, 150) * 1
Next j
Next i
End Sub

VBA to delete rows based on cell value

I am trying to do the following :
VBA to lookup a value from a particular cell
Match these values in a particular column in specified sheets
Delete all rows from the sheet if the value do not match
I have tried the following - the code doesn't seem to function
Sub Delete()
Dim List As Variant
Dim LR As Long
Dim r As Long
List = Worksheets("Sheet1").Cells(28, "C").Value
LR = Range("E" & Rows.Count).End(xlUp).Row
For r = LR To 1 Step -1
If IsError(Application.Match(Range("E" & r).Value, List, False)) Then
Worksheets("Sheet2").Range("A1:AA36429").Rows(r).Delete
End If
Next r
End Sub
Try this:
Sub Delete()
Dim i As Integer
Dim LR As Long
Dim List As Variant
LR = Range("E" & Rows.Count).End(xlUp).Row
List = Worksheets("Sheet1").Cells(28, "C").Value
For i = 1 To LR
If Cells(i, "E").Value = List Then
Worksheets("Sheet1").Rows(i).Delete
End If
Next i
End Sub
I think you have a few ways of going about this, but the quickest way I know of is to use MATCH to compare values in a range to values in an array. Please note that this has a limit to 4000 or so values to compare before it fails. For your purposes, I think the following will work:
Sub test1()
Dim x As Long
Dim array1() As Variant
Dim array2() As Variant
array1 = Array("ABC", "XYX")
array2 = Range("A1:A2")
If IsNumeric(Application.Match(Range("A1").Value, array1, 0)) Then
x = 1
ElseIf IsNumeric(Application.Match(Range("A1").Value, array2, 0)) Then
x = IsNumeric(Application.Match(Range("A1").Value, array2, 0))
End If
'If x is not found in these arrays, x will be 0.
MsgBox x
End Sub
Another similar way is the following:
Sub test2()
Dim array1() As Variant
Dim FilterArray() As String
Dim x As Variant
x = Range("A1").Value
array1 = Array("ABC", "RANDOM", "VBA")
FilterArray = Filter(SourceArray:=array1, _
Match:=strText, _
Include:=True, _
Compare:=vbTextCompare)
If UBound(FindOutArray) = -1 Then
MsgBox "No, Array doesn't contain this item - " & x
Else
MsgBox "Yes, Array contains this item - " & x
End If
End Sub
So if we were to incorporate that all together (and I tested this btw):
Sub Delete()
Dim i As Integer
Dim LR As Long
Dim List() As Variant
Dim x As Long
LR = Range("E" & Rows.count).End(xlUp).Row
List = Worksheets("Sheet1").Range("A1:A2").Value
For i = 1 To LR
If IsNumeric(Application.Match(Cells(i, "E").Value, List, 0)) Then
Worksheets("Sheet1").Cells(i, "E").Value = ""
End If
Next i
Worksheets("Sheet1").Columns("E").SpecialCells(xlCellTypeBlanks).Cells.Delete
End Sub
This will set the cells that have values that are found in the array to blanks. Once the loop is finished, then the blank cells are deleted. If you want to shift the entire rows up, then use this as the last line instead:
Worksheets("Sheet1").Columns("E").SpecialCells(xlCellTypeBlanks).EntireRow.Delete

VBA Excel adding values to dictionary

Alright, maybe I've just been looking at this for too long but I keep getting an expected expression error, which I believe is just a syntax issue but I'm not entirely sure. I'm looping through one sheet and adding unique values of one column as keys to the dictionary while adding the numbers that correspond to the keys together. For example, if I have:
A 2
B 3
B 4
A 5
C 6
I want the dictionary to look like:
A 7
B 7
C 6
Here's my code, any help is appreciated.
Sub Name()
Dim rng As Range
Dim x As Integer
Dim ranga As String
Dim dico As Dictionary
Set dico = New Dictionary
Dim var As Variant
Dim lastrow As Integer
With Worksheets("Sheet1")
lastrow = Range("A" & .Rows.Count).End(xlUp).Row
ranga = "C6" & ":" & "C" & CStr(lastrow)
Set rng = Range(ranga)
For Each var In rng.Cells
If dico.Exists(var.Value) Then
dico(var.Value) = dico(var.Value) + var.Offset(0, 4).Value
Else
dico.add var.Value, var.Offset(0, 4).Value
End If
Next var
End With
With Worksheets("Sheet2")
Set rng = Range("A2")
Dim i As Integer
i = 0
For Each var In dico.Keys
rng.Offset(i).Value = var
rng.Offset(i, 1).Value = dico(var)
Next var
End With
End Sub
I am new to stackoverflow, so I am a but unsure of the appropriate etiquette, but here is a working solution.
Public Sub dict_counter()
Dim counter As New Dictionary
Dim key As Range: Set key = ThisWorkbook.Sheets("sheet1").Range("A1")
While Not IsEmpty(key)
If counter.Exists(key.Value) Then
counter(key.Value) = counter(key.Value) + key.Offset(ColumnOffset:=1)
Else
counter(key.Value) = key.Offset(ColumnOffset:=1)
End If
Set key = key.Offset(RowOffset:=1)
Wend
'Obviously you can output the dict contents to whatever location
'is convenient
Dim k As Variant
For Each k In counter
Debug.Print k; counter(k)
Next k
End Sub
Instead of
dico(var.Value) = dico(var.Value) + var.Offset(0, 4).Value
It should be
dico.Item(var.Value) = dico(var.Value) + var.Offset(0, 4).Value
See MSDN
Also, if you use With, you have to actually put leading .'s where you want to use methods or properties of it like this:
With Worksheets("Sheet1")
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
End With
See MSDN

VBA - Split string into individual cells

I have a string compressed into one cell. I need to separate each part of the string into their own cell, while copying the data from the same row.
Here is my example data:
A | B
Row1 ABC ABD ABE ABF | CODE1
Row2 BCA DBA EBA FBA | CODE2
Row3 TEA BEF | CODE3
The result would be:
A B
ABC CODE1
ABD CODE1
ABE CODE1
ABF CODE1
BCA CODE2
DBA CODE2
EBA CODE2
FBA CODE2
TEA CODE3
BEF CODE3
I have about 2000 rows and would literally take 30 years to use the text to column function for this. So I am trying to write a vba macro. I think I am making this harder than it needs to be. Any thoughts or pushes in the right direction would be appreciated. Thanks in advance for any help.
This will work, (but it's mighty inefficient unless you do it in an array... nevertheless for only 2000 rows, you won't even notice the lag)
Function SplitThis(Str as String, Delimiter as String, SerialNumber as Long) As String
SplitThis = Split(Str, Delimiter)(SerialNumber - 1)
End Function
Use it as
= SPLITTHIS("ABC EFG HIJ", " ", 2)
' The result will be ...
"EFG"
You will still need to put in a whole lot of extra error checking, etc. if you need to use it for a distributed application, as the users might put in values greater than the number of 'split elements' or get delimiters wrong, etc.
I like iterating over cells for problems like this post.
' code resides on input sheet
Sub ParseData()
Dim wksOut As Worksheet
Dim iRowOut As Integer
Dim iRow As Integer
Dim asData() As String
Dim i As Integer
Dim s As String
Set wksOut = Worksheets("Sheet2")
iRowOut = 1
For iRow = 1 To UsedRange.Rows.Count
asData = Split(Trim(Cells(iRow, 1)), " ")
For i = 0 To UBound(asData)
s = Trim(asData(i))
If Len(s) > 0 Then
wksOut.Cells(iRowOut, 1) = Cells(iRow, 2)
wksOut.Cells(iRowOut, 2) = s
iRowOut = iRowOut + 1
End If
Next i
Next iRow
MsgBox "done"
End Sub
Assuming your data is on the first sheet, this populates the second sheet with the formatted data. I also assume that the data is uniform, meaning there is the same type of data on every row until the data ends. I did not attempt the header line.
Public Sub FixIt()
Dim fromSheet, toSheet As Excel.Worksheet
Dim fromRow, toRow, k As Integer
Dim code As String
Set fromSheet = Me.Worksheets(1)
Set toSheet = Me.Worksheets(2)
' Ignore first row
fromRow = 2
toRow = 1
Dim outsideArr() As String
Dim insideArr() As String
Do While Trim(fromSheet.Cells(fromRow, 1)) <> ""
' Split on the pipe
outsideArr = Split(fromSheet.Cells(fromRow, 1), "|")
' Split left of pipe, trimmed, on space
insideArr = Split(Trim(outsideArr(0)), " ")
' Save the code
code = Trim(outsideArr(UBound(outsideArr)))
' Skip first element of inside array
For k = 1 To UBound(insideArr)
toSheet.Cells(toRow, 1).Value = insideArr(k)
toSheet.Cells(toRow, 2).Value = code
toRow = toRow + 1
Next k
fromRow = fromRow + 1
Loop
End Sub
Let me try as well using Dictionary :)
Sub Test()
Dim r As Range, c As Range
Dim ws As Worksheet
Dim k, lrow As Long, i As Long
Set ws = Sheet1 '~~> change to suit, everything else as is
Set r = ws.Range("B1", ws.Range("B" & ws.Rows.Count).End(xlUp))
With CreateObject("Scripting.Dictionary")
For Each c In r
If Not .Exists(c.Value) Then
.Add c.Value, Split(Trim(c.Offset(0, -1).Value))
End If
Next
ws.Range("A:B").ClearContents
For Each k In .Keys
lrow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
If lrow = 1 Then i = 0 Else i = 1
ws.Range("A" & lrow).Offset(i, 0) _
.Resize(UBound(.Item(k)) + 1).Value = Application.Transpose(.Item(k))
ws.Range("A" & lrow).Offset(i, 1).Resize(UBound(.Item(k)) + 1).Value = k
Next
End With
End Sub
Above code loads all items in Dictionary and then return it in the same Range. HTH.
Here is an approach using a User Defined Type, Collection and arrays. I've been using this lately and thought it might apply. It does make writing the code easier, once you get used to it.
The user defined type is set in a class module. I called the type "CodeData" and gave it two properties -- Code and Data
I assumed your data was in columns A & B starting with row 1; and I put the results on the same worksheet but in columns D & E. This can be easily changed, and put on a different worksheet if that's preferable.
First, enter the following code into a Class Module which you have renamed "CodeData"
Option Explicit
Private pData As String
Private pCode As String
Property Get Data() As String
Data = pData
End Property
Property Let Data(Value As String)
pData = Value
End Property
Property Get Code() As String
Code = pCode
End Property
Property Let Code(Value As String)
pCode = Value
End Property
Then put the following code into a Regular module:
Option Explicit
Sub ParseCodesAndData()
Dim cCodeData As CodeData
Dim colCodeData As Collection
Dim vSrc As Variant, vRes() As Variant
Dim V As Variant
Dim rRes As Range
Dim I As Long, J As Long
'Results start here. But could be on another sheet
Set rRes = Range("D1:E1")
'Get Source Data
vSrc = Range("A1", Cells(Rows.Count, "B").End(xlUp))
'Collect the data
Set colCodeData = New Collection
For I = 1 To UBound(vSrc, 1)
V = Split(vSrc(I, 1), " ")
For J = 0 To UBound(V)
Set cCodeData = New CodeData
cCodeData.Code = Trim(vSrc(I, 2))
cCodeData.Data = Trim(V(J))
colCodeData.Add cCodeData
Next J
Next I
'Write results to array
ReDim vRes(1 To colCodeData.Count, 1 To 2)
For I = 1 To UBound(vRes)
Set cCodeData = colCodeData(I)
vRes(I, 1) = cCodeData.Data
vRes(I, 2) = cCodeData.Code
Next I
'Write array to worksheet
Application.ScreenUpdating = False
rRes.EntireColumn.Clear
rRes.Resize(rowsize:=UBound(vRes, 1)) = vRes
Application.ScreenUpdating = True
End Sub
Here is the solution I devised with help from above. Thanks for the responses!
Sub Splt()
Dim LR As Long, i As Long
Dim X As Variant
Application.ScreenUpdating = False
LR = Range("A" & Rows.Count).End(xlUp).Row
Columns("A").Insert
For i = LR To 1 Step -1
With Range("B" & i)
If InStr(.Value, " ") = 0 Then
.Offset(, -1).Value = .Value
Else
X = Split(.Value, " ")
.Offset(1).Resize(UBound(X)).EntireRow.Insert
.Offset(, -1).Resize(UBound(X) - LBound(X) + 1).Value = Application.Transpose(X)
End If
End With
Next i
Columns("B").Delete
LR = Range("A" & Rows.Count).End(xlUp).Row
With Range("B1:C" & LR)
On Error Resume Next
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
On Error GoTo 0
.Value = .Value
End With
Application.ScreenUpdating = True
End Sub