VBA concatenate two ranges and create new range in VBA - vba

Is it possible to create a new range that concatenates the 3 ranges together into a new range? For example, the first value of the range would be The-Ball-Park and the second value would be The-Train-Station, so on and so forth over X amount of rows. If possible, I would like it so script would skip over completely blank rows.
I would like to save the range into a variable, I would Not like to have the range be inserted in the sheet.
Thank you!
Key1
Key2
Key3
The
Ball
Park
The
Train
Station
The
Fast
Lane

You might need to make it a bit more clever if you don't intend on using exactly 3 inputs for each output.
Let me know.
Option Explicit
Option Base 1
Sub ConcatRangeToArray()
'Variables
Dim I As Integer
Dim OG_Array
Dim Output_Array
Dim RG As Range
'Set this to whatever range you need concatenated
Set RG = Sheet1.Range("A2:C4") '<<< range to concatenate
OG_Array = RG
ReDim Output_Array(1 To UBound(OG_Array, 1))
'Preform concatenation
For I = 1 To UBound(OG_Array, 1)
Output_Array(I) = OG_Array(I, 1) & "-" & OG_Array(I, 2) & "-" & OG_Array(I, 3)
Debug.Print Output_Array(I)
Next I
End Sub
Example of spreadsheet I used:
Example of output:

Related

Using VBA DateDiff to compare multiple Dates, output the difference and then compare output against another cell

I've got a spreadsheet which is used to record multiple times/dates where services were rendered.
In the spreadsheet the columns I'm interested in comparing start at row 9, column BA-BB, BC-BD, BE-BF, BG-BH, BI-BJ, BK-BL, BM-BN, BO-BP, BQ-BR for each of the rows in minutes. I then want to add all the total differences between the dates and finally compare that total with with AF9 if populated or if that cell is blank AG9.
I want the Macro to loop through all the rows producing a total units for each row at the end of the sheet (Column BU)
The purpose of the spreadsheet is to check that the value populated in either AF or AG is in fact correct if we were to work out the difference in times and convert to units anyway.
What I've been working on so far is:
Sub CalculateDate()
Dim Result, RowNo As Long
Dim FirstDate, SecondDate As Date
Dim ws As Worksheet
Set DateCompare = ActiveWorkbook.Sheets("Master")
Set DateCompareRng = Support.Range("BA2", Support.Cells(Rows.Count, "BA").End(xlUp).Offset(0, 18))
Set DateCompareArr = DateCompareRng.Value2
RowNo = 1
Do Until DateCompare.Cells(RowNo, 1) = ""
FirstDate = DateCompare.Cells(RowNo, 1)
SecondDate = DateCompare.Cells(RowNo, 2)
DateCompareArr(FirstDate, 3) = DateDiff("m", FirstDate, SecondDate)
RowNo = RowNo + 1
Loop
End Sub
The above is my shoddy attempt at amending some logic someone else provided on the forums to a similar question. I don't want to compare specific dates I enter though as the dates will all be different throughout the cells.
I've never used this type of function before in VBA so not really sure on how to go about changing it to suit my needs. If I can manage to loop through of of the start/end times I can probably work out how to loop through additional columns and compare against another 2 columns after that.
Some sample date is:
Start 1 | Start 2
23/03/2018 12:00 | 2018-03-23 16:00 GMT
Difference = (In minutes)
Compare Difference to:
Total Units(Column AF) = 600(this is 600 minutes)
Sorry that this is such a long question. I'm just really stuck with getting started on this problem
I like your attempt, you are on the right track. Below is tested sample code, which I think will provide you with the answer you're seeking. Good luck and happy coding
Public Sub CalculateDate()
'While I don't recommend hard coding the start and end of your range
'for this example, I thought it would simplify things.
'Start of the range is the first cell, which in your example seems
'like BA9
Const RANGE_START As String = "BA9"
'End of the range is the last cell in right most column, which
'in your example was BR. I chose the 18th row, but you could
'make it whatever you need
Const RANGE_END As String = "BR18"
'Declare a worksheet variable as you've done
'And set it to the worksheet in the ActiveWorkbook as you've done
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Master")
'Declare the range that contains the values you need to sum
Dim rngToSum As Range
'And set it to the range in the WorkSheet
'In this case the range will be
'ws.Range("BA9:BR18")
Set rngToSum = ws.Range(RANGE_START & ":" & RANGE_END)
'Declare an index to be used in the for loop below
'as we loop through each column in the row the
'code is summing
Dim nDx As Integer
'Declare a range for the row to be worked on
Dim rngRow As Range
'Declare a string value that will hold the
'output range(row, cell)
Dim outStr As String
'Declare an output range variable
Dim outRng As Range
'Declare a variable to hold the summation of the
'row values you want to add together
Dim rowSum As Long
'Outter loop to loop through each of the rows in the
'defined range
For Each rngRow In rngToSum.Rows
'Initialize/Reinitialize the rowSum to 0 for each row
rowSum = 0
'Inner loop to loop throug all the columns in the range
'you want to add together
For nDx = 1 To rngToSum.Columns.Count Step 2
'NOTE--> DateDiff uses lower case N for minutes, not lower case M
'I noticed that in your sample code
rowSum = rowSum + DateDiff("n", rngRow.Value2(1, nDx), rngRow.Value2(1, nDx + 1))
Next
'Completed adding all the columns together
'Assign the outPut row, cell for the output Range
'The formula below will concatenate the
'letter A with the current row number
'For example if the current row number is 9
'outStr will equal A9
outStr = "A" & rngRow.Row
'I always use Value2 since it is faster than the
'Text or Value properties of the range object
ws.Range(outStr).Value2 = rowSum
Next
End Sub

VBA Excel - Using a variable to determine cell location

I don't exactly know how to formulate my question since so I'll just give an example which should make it clear.
Basically I want to use a variable to determine what cell I have to use.
For example, I count the amount of rows my sheet has and store it in a variable. Now I want to use that variable to determine a range.
Range("K2:M*").Select
Now where I have the * I want to use the rows I counted and stored in a variable earlier on.
How can I do this?
A better approach to such things is using the alternate form of Range's arguments, the one with cells. Why? because is really easier to dealing with numerically-indexed columns than the "A1" type of address. For example:
Dim col1 As Long
Dim row1 As Long
Dim col2 As Long
Dim row2 As Long
' Some code to initialize/calculate
Let col1 = 11 'K
Let row1 = 2
Let col2 = 13 'M
Let row2 = SomeFunctionThatCalculates()
With Worksheets("Whatever") ' Replace with a valid Worksheet object
Call .Range( _
.Cells(row1,col1), _
.Cells(row2,col2) _
).Select
End With
Of course, for rows a quick way is the one given by Rory in comments.
It's simple:
sub Test()
Dim Var1 as string
Var1 = 'Whatever your variable is
Range("K2:M" & Var1).select
End sub
I think your question was to how to get the range of the worksheet selected with the ability to scale to the bottom of the sheet, excluding headers - thus starting with 2:bottom. i tend to use the usedrange property.
sub test
dim rowcount as double
rowcount = activesheet.usedrange.rows.count
Range("K2:M" & rowcount).Select
end sub

vb excel drag formula for variable number of rows

I have a excel sheet which I am populating using a VB program. The output sheet can have variable number of rows but has 6 columns (A:F). Now I want the column G to have hex2dec of all the rows in column A. Here's an example: Say column A has 400 rows (A1:A400) then I want G1:G400 to have values HEX2DEC(A1:A400). But this is just an example the rows can vary. I have this code so far:
Sub DataMod()
Dim i As Long, R3 As Long
R3 = 1
For i = 1 To sheet.UsedRange.Rows.Count
sheet.Cells(i, 7).Formula = "=HEX2DEC" & sheet.Cells(R3, 1)
R3 = R3 + 1
Next i
End Sub
But it's not working.
Review your HEX2DEC formula string
it doesn't include the necessary ()
the Cells() would return the value of the target cell, not its address (i.e. the result would be =HEX2DEC(1234) instead of =HEX2DEC(A1) - which may or may not be a problem
you could use variable i instead of R3, they both increment from the same starting point at the same increment
I recommend to use FormulaR1C1, you do not have variants there
Sub DataMod()
Dim C As Range
For Each C In ActiveSheet.UsedRange.Columns(1).Cells
C(1, 7).FormulaR1C1 = "=HEX2DEC(RC[-6])"
Next C
End Sub
The danger of UsedRange is that it might include any header rows, so you might want to get around this by selecting the input range manually before you fire your Sub() and work with the Selection object, e.g.
For Each C In Selection.Columns(1).Cells
Try This:
Sub DataMod()
' Get the number of rows used in Column A:
Dim NumRows as Long
NumRows = Range("A1").End(xlDown).Row
' Put the formulas in Column G all at once:
Range("G1:G" & NumRows).FormulaR1C1 = "=Hex2Dec(RC1)"
End Sub

excel vba moving non-contiguous range selection to an array

In the situation where the user select two non-contiguous column ranges i wrote the following:
Dim count long
Dim points variant
Dim i long
Set user_range = ActiveWindow.RangeSelection
count = user_range.count / 2
ReDim points(1 To count, 1 To 2)
For i = 1 To count
MsgBox "value is" & user_range.Areas.Item(1).Value(i,1)
points(i, 1) = user_range.Areas.Item(1).Value(i,1)
points(i, 2) = user_range.Areas.Item(2).Value(i,1)
Next i
But i get an object error when i try this. Am i indexing Value wrong?
This should work right? Is there an easier way to do this?
Any help is greatly appreciated!
Thanks,
Russ
I'm afraid your code does not compile. First of all, you need to declare your variables correctly. You should also use Option Explicit.
Option Explicit
Dim count As Long
Dim points As Variant
Dim i As Long
Dim user_range As Range
The count and ReDim lines are OK, but you are assuming that the two selections are both the same size. Will that always be the case?
Then I'm not sure what it is you want to do, but I'm guessing you just want to save the values in user_range into points.
You need to adress them a bit different:
points(i, 1) = user_range.Areas(1).Cells(i, 1).Value 'Selection 1
points(i, 2) = user_range.Areas(2).Cells(i, 1).Value 'Selection 2

Stuck at deleting a record stored in a variant datatype

Ok I have tried these and grasped some view on variants and I have written these code
Sub main()
Dim Vary As Variant
Vary = Sheet1.Range("A1:D11").Value
For i = 1 To UBound(Vary)
For j = i + 1 To UBound(Vary)
If Vary(i, 1) = Vary(j, 1) Then
'I should delete the vary(j,1) element from vary
'in excel sheet we use selection.entirerow.delete
End If
Next j
Next i
End Sub
This is the sample I tried
A B C D
1 somevalues in BCD columns
2
3
1
Now Delete the 4th row don think I'm working for unique records I'm just learning stuff to do and while I was learning variant I am stuck at this point deleting a complete row stored in variant
I have stored (A1:D11).value in variant
Now how can I delete the A6 element or row in variant so that I can avoid it while I copy the variant to some other sheet?
Can I also delete the C AND B columns in variant so that when i do transpose it wont copy the C and B columns?
I don't know what exactly a variant is - I was thinking to take a set of range and do operations like what we do for an excel sheet then take that variant and transpose it back to sheet.
Is that the right way of thinking or did I misunderstand the use of variants?
`variant(k,1)=text(x)` some array shows mismatch ? whats wrong?
If you are planning on using a varray to look at cells in each row to decide if you should delete the row or not, you should loop through your varray backwards, the same way you would if you did a for loop through the cell range. Since you are starting on row 1, the variable i will always equal the row number the element was located on, so you can use that to delete the proper row.
Here's a sample (more simple than what you are trying to do, though) that will delete each row in which the cells in columns A and B are the same.
Sub test()
Dim varray As Variant
varray = Range("A1:B11").Value
For i = UBound(varray, 1) To 1 Step -1
If varray(i, 1) = varray(i, 2) Then
Cells(i, 1).EntireRow.Delete
End If
Next
End Sub
Notes of interest:
UBound(varray, 1) gives the count of the rows
UBound(varray, 2) gives the count of the columns
One workaround without a second array is to introduce a deliberate error into an element you want to replace, then use SpecialCells to delete the cell after dumping the variant array back over the range. This sample introduces an error into the array position corresponding to A6 (outside the loop as its an example), then when the range is dumped to E1, the SpecialCell error removal shifts F6:H6 into E6:G6. ie
pls save before testing - this code will overwrite E6:H11 in the first worksheet
Sub main()
Dim Vary As Variant
Dim rng1 As Range
Set rng1 = Sheets(1).Range("A1:D11")
Set rng2 = rng1.Offset(0, 4)
Vary = rng1.Value2
For i = 1 To UBound(Vary)
For j = i + 1 To UBound(Vary)
'your test here
Next j
Next i
Vary(6, 1) = "=(1 / 0)"
With rng2
.Value2 = Vary
On Error Resume Next
.SpecialCells(xlFormulas, xlErrors).Delete xlToLeft
End With
End Sub