How to duplicate and transpose VBA - excel

My code blow, was made for only 3 years, (2016, 2017 & 2018). but now i have added 4 more years, but i dont know how to fit the description, so that i adds 4 more classes and four more on row Q Ark1. So that it fits with years 2016 to 2022. The code is added below, it transposes the information from Ark2 to Ark1.
I really hope you can help.
Sub TransposeAH()
Const cSheet1 As Variant = "Ark2" ' Sheet1 Name/Index
Const cSheet2 As Variant = "Ark1" ' Sheet2 Name/Index
Const cFirst As Integer = 23 ' First Row Number
Const cCol1First As Variant = "A" ' Range1 First Column Letter/Number
Const cCol1Last As Variant = "C" ' Range1 Last Column Letter/Number
Const cCol2First As Variant = "E" ' Range2 First Column Letter/Number
Const cCol2Last As Variant = "G" ' Range2 Last Column Letter/Number
Const cColumns As Integer = 1 ' Number of New Columns
Const cFirstCell As String = "N1" ' Target Range First Cell Address
Dim vntH As Variant ' Range2 Headers
Dim vnt2 As Variant ' Range2 Array
Dim vnt3 As Variant ' Range1 Temp Array (if value is "")
Dim vnt1 As Variant ' Range1 Array
Dim vntT As Variant ' Target Array
Dim LastUR As Long ' Last Used Row
Dim i As Long ' Arrays Row Counter
Dim j As Integer ' Arrays Column Counter
Dim k As Long ' Target Array Rows Counter
Dim m As Integer ' Range1 Temp Array Column Counter
' From Sheet1 to Arrays.
With Worksheets(cSheet1)
' Calculate Last Used Row.
With .Range(.Cells(cFirst, cCol1First), .Cells(.Rows.Count, cCol2Last))
If .Find("*", .Cells(.Rows.Count, .Columns.Count), -4123, , 1) _
Is Nothing Then Exit Sub
LastUR = .Find("*", , , , , 2).Row
End With
' Paste ranges into arrays.
vnt1 = .Range(.Cells(cFirst, cCol1First), .Cells(LastUR, cCol1Last))
vnt2 = .Range(.Cells(cFirst, cCol2First), .Cells(LastUR, cCol2Last))
vntH = .Range(.Cells(cFirst - 1, cCol2First), _
.Cells(cFirst - 1, cCol2Last))
End With
' Resize Target Array.
ReDim vntT(1 To UBound(vnt2) * UBound(vnt2, 2), _
1 To cColumns + UBound(vnt1, 2))
' Write Range2 Array to Target Array.
For i = 1 To UBound(vnt2)
For j = 1 To UBound(vnt2, 2)
k = k + 1
vntT(k, 1) = vntH(1, j)
vntT(k, 2) = vnt2(i, j)
Next
Next
' Resize Range1 Temp Array (if value is "")
ReDim vnt3(1 To 1, 1 To UBound(vnt1, 2))
' Copy first line of Range1 Array to Range1 Temp Array.
For m = 1 To UBound(vnt3, 2)
vnt3(1, m) = vnt1(1, m)
Next
' Write Range1 Array to Target Array.
k = 0
For i = 1 To UBound(vnt1)
For j = 1 To UBound(vnt1, 2)
k = k + 1
For m = 1 To UBound(vnt2, 2)
If vnt1(i, m) <> "" Then
If vnt1(i, m) <> vnt3(1, m) Then
vnt3(1, m) = vnt1(i, m)
End If
End If
vntT(k, m + cColumns) = vnt3(1, m)
Next
Next
Next
' Paste Target Array into Target Range resized
' from Target Range First Cell Address.
With Worksheets(cSheet2).Range(cFirstCell)
.Resize(UBound(vntT), UBound(vntT, 2)) = vntT
End With
End Sub

Related

How to count the number of unique strings separated by a space in each cell?

I have strings of numbers in one column, each cell contains from 1 to n sequences separated by a space e.g.
1001
2034 2034 2034
3456 3456 3456
is there a way to count how many unique sequences exist in each cell and place this number in the adjacent cell?
So e.g.
Column 1 Column 2
1001 1
2034 2034 2034 1
3456 3456 3456 1
3455 3455 5674 2
1234 3456 3456 4568 6754 4
So, I have managed to get to this point but how do I go about the range and the loop to basically print the result to each cell (to the right) of the analysed range?
Sub CountStuff()
Dim c As Collection
Set c = New Collection
ary = Split(ActiveCell.Value, " ")
On Error Resume Next
For Each a In ary
c.Add a, CStr(a)
Next a
On Error GoTo 0
Debug.Print c.Count
End Sub
Following from my comment above:
Sub CountStuff()
Dim col As Collection, c As Range, arr, v, rng As Range
Set rng = ActiveSheet.Range("A2:A100") 'for example
For Each c In rng.Cells
If Len(c.Value) > 0 Then
arr = Split(c.Value, " ")
Set col = New Collection
For Each v In arr
If Len(v) > 0 Then
On Error Resume Next 'ignore error on duplicate key
col.Add v, CStr(v)
On Error GoTo 0
End If
Next v
c.Offset(0, 1).Value = col.Count 'put count one cell over
End If
Next c
End Sub
Count Unique Substrings (UDF)
The Function
Option Explicit
Function CountUniqueSubStrings( _
ByVal SplitString As String, _
Optional ByVal Delimiter As String = " ") _
As Long
Dim SubStrings() As String: SubStrings = Split(SplitString, Delimiter)
Dim ssCount As Long: ssCount = UBound(SubStrings)
Dim usCount As Long
If ssCount < 1 Then
usCount = ssCount + 1
Else
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim cString As String
Dim n As Long
For n = 0 To ssCount
cString = SubStrings(n)
If Len(cString) > 0 Then
dict(SubStrings(n)) = Empty
End If
Next n
usCount = dict.Count
End If
CountUniqueSubStrings = usCount
End Function
Excel Example
=CountUniqueSubStrings(A1)
VBA Example
Sub CountUniqueSubStringsTEST()
' Define constants.
Const sFirst As String = "A2"
Const dFirst As String = "B2"
Const Delimiter As String = " "
' Create a reference to the worksheet.
Dim ws As Worksheet: Set ws = ActiveSheet
' Maybe better examples:
'Set ws = Sheet1
'Set ws = ThisWorkbook.Worksheets("Sheet1")
' Create a reference to the Source Column Range.
Dim srg As Range
Dim rCount As Long
With ws.Range(sFirst)
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If fCell Is Nothing Then Exit Sub
rCount = lCell.Row - .Row + 1
Set srg = .Resize(rCount)
Debug.Print srg.Address
End With
' Write values from the Source Column Range to the Data Array.
Dim Data As Variant
If rCount = 1 Then ' one cell only
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = srg.Value
Else
Data = srg.Value
End If
' Replace the values in the Data Array with the 'unique counts'.
Dim r As Long
For r = 1 To rCount
Data(r, 1) = CountUniqueSubStrings(Data(r, 1), Delimiter)
Next r
' Create a reference to the Destination Column Range.
Dim drg As Range: Set drg = ws.Range(dFirst).Resize(rCount)
' Write the 'unique counts' from the Data Array
' to the Destination Column Range.
drg.Value = Data
' Clear the contents below the Destination Column Range.
With drg.Cells(1)
.Resize(.Worksheet.Rows.Count - .Row - rCount + 1) _
.Offset(rCount).ClearContents
End With
End Sub

Copy each row n times

I need to copy every row 12 times from sheet1 to sheet 2.
Right now I copy the first row 12 times but row 2 is only copied once. I have provided a sample of the sheet and my code. Hope you guys can help.
My data starts in row a13
As a bonus I need to transpone the values in columns E:P
The reason why I need to do this is because all values in E:P is the value for each month and the values in A:C is the attributes that is necessary to identify the values in month to a certain car with year, registrations number and service
Sub copyEachRow()
Dim i As Integer
For i = 1 To 12
Sheets("asheet1").Range("A13").CurrentRegion.Copy Sheets("sheet2").Cells(i + 13, "a")
Next i
End Sub
Copy Transpose
Option Explicit
Sub copyEachRow()
Const srcName As String = "Sheet1"
Const sFirst As String = "A13"
Const dstName As String = "Sheet2"
Const dFirst As String = "A13"
Dim wb As Workbook
Set wb = ThisWorkbook
' Source Range to Source Array.
Dim Source As Variant
Source = wb.Worksheets(srcName).Range(sFirst).CurrentRegion.Value
Dim rCount As Long
rCount = UBound(Source, 1)
Dim Dest As Variant
ReDim Dest(1 To rCount * 12, 1 To 4)
' Write headers
Dim j As Long
For j = 1 To 3
Dest(1, j) = Source(1, j)
Next j
Dest(1, 4) = "Value"
' Write body.
Dim i As Long
Dim k As Long
Dim n As Long
For i = 2 To UBound(Source, 1)
For n = 1 To 12
k = k + 1
For j = 1 To 3
Dest(k, j) = Source(i, j)
Next j
Dest(k, 4) = Source(i, 3 + n)
Next n
Next i
' Destination Array to Destination Range.
With wb.Worksheets(dstName).Range(dFirst).Resize(, 4)
.Resize(.Worksheet.Rows.Count - .Row + 1).ClearContents
.Resize(k).Value = Dest
End With
End Sub
Sub copyEachRow()
Range("A1:C32").Select
Selection.Copy
Sheets("Sheet2").Select
Range("A1").Select
ActiveSheet.Paste
Dim I As Long
Dim xCount As Integer
xCount = 11
For I = Range("A" & Rows.CountLarge).End(xlUp).Row To 1 Step -1
Rows(I).Copy
Rows(I).Resize(xCount).Insert
Next
Application.CutCopyMode = False
End Sub
you can adapt this piece of code to your need:
Sub copyEachRow()
Dim cel As Range
With Sheet2
For Each cel In Sheet1.Range("A13", Sheet1.Cells(.Rows.Count, 1).End(xlUp))
cel.EntireRow.Copy .Cells(.Rows.Count, 1).End(xlUp).Offset(1).Resize(12)
Next
End With
End Sub
just place a header in Sheet2 column A cell after which you want to paste data from

How do I copy to another worksheet specific columns and rows

I have a worksheet with columns A:M and rows 1 to 5000. I would like to copy rows to another worksheet when a number greater then 0 is added to column L and M. I also only require columns A:F and K:M on the new worksheet
you'll need to name the source and target worksheets, but below code should do the trick.
Sub SheetTransfer()
Dim i As Long
Dim j As Long
Dim t As Double
Dim LastRow As Long
Dim ws1 As String
Dim ws2 As String
'name source worksheet here
ws1 = "Sheet1"
'name target worksheet here
ws2 = "Sheet2"
'set the threshold value for a row to be copied over
t = 0
' set to column L
j = 12
For i = 1 To 5000
If Worksheets(ws1).Cells(i, j).Value > 0 Or Cells(i, j + 1).Value > t Then
'find last row of target worksheet
With Worksheets(ws2)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'copy/paste columns A-F
Worksheets(ws1).Range(Cells(i, 1), Cells(i, 6)).Copy
Worksheets(ws2).Cells(LastRow + 1, 1).PasteSpecial xlPasteValues
'copy paste columns K-M
Worksheets(ws1).Range(Cells(i, 11), Cells(i, 13)).Copy
Worksheets(ws2).Cells(LastRow + 1, 11).PasteSpecial xlPasteValues
End If
Next i
End Sub
Copy Data to Other Worksheet
Adjust the values in the constants section to fit your needs.
The Code
Sub AM5000()
' Source
Const cVntSource As Variant = "Sheet1" ' Source Worksheet Name/Index
Const cStrRange1 As String = "A1:F5000" ' Source 1 Range Address
Const cStrRange2 As String = "K1:M5000" ' Source 2 Range Address
Const cIntCol1 As Integer = 2 ' Source Range Criteria Column 1
Const cIntCol2 As Integer = 3 ' Source Range Criteria Column 2
' Target
Const cVntTarget As Variant = "Sheet2" ' Target Worksheet Name/Index
Const cStrTarget As String = "A1" ' Target First Cell Address
Dim vnt1 As Variant ' Source 1 Array
Dim vnt2 As Variant ' Source 2 Array
Dim vntTarget As Variant ' Target Array
Dim i As Integer ' Source Arrays Row Counter
Dim j As Integer ' Arrays Column Counter
Dim k As Integer ' Target Array Row Counter
' Paste Source Ranges into Source Arrays.
With Worksheets(cVntSource)
vnt1 = .Range(cStrRange1)
vnt2 = .Range(cStrRange2)
End With
' Count the number of rows for Target Array.
For i = 1 To UBound(vnt2)
If vnt2(i, cIntCol1) > 0 And vnt2(i, cIntCol2) > 0 Then
k = k + 1
End If
Next
' Write Source Arrays to Target Array.
ReDim vntTarget(1 To k, 1 To UBound(vnt1, 2) + UBound(vnt2, 2))
k = 0
For i = 1 To UBound(vnt2)
If vnt2(i, cIntCol1) > 0 And vnt2(i, cIntCol2) > 0 Then
k = k + 1
For j = 1 To UBound(vnt1, 2)
vntTarget(k, j) = vnt1(i, j)
Next
For j = 1 To UBound(vnt2, 2)
vntTarget(k, j + UBound(vnt1, 2)) = vnt2(i, j)
Next
End If
Next
' Paste Target Array into Target Range.
With Worksheets(cVntTarget).Range(cStrTarget)
'.Parent.Cells.ClearContents
.Resize(UBound(vntTarget), UBound(vntTarget, 2)) = vntTarget
End With
End Sub

How do i set ID for data via VBA

In the picture of the sheet I get my data from "Ark2" and the sheet I get the data to "Ark1". In Ark1 I want want to give an ID for the data. I show an example in yellow, grey, green and blue colours. I want the text ID to stand as it does in the example row "K".
the code is added at the end..
Sub MyProcedure()
a = Worksheets("ark1").Cells(Rows.Count, 1).End(xlUp).Row
MsgBox (a)
End Sub
Private Sub CommandButton1_Click()
Dim nøgletal As String, år As Integer
Worksheets("Ark2").Select
nøgletal = Range("B2")
år = Range("C2")
Worksheets("Ark1").Select
Worksheets("Ark1").Range("A4").Select
ThisWorkbook.Worksheets("Ark1").Range("A1:A100").Value = ThisWorkbook.Worksheets("Ark2").Range("A12:A100").Value
ThisWorkbook.Worksheets("Ark1").Range("B1:B100").Value = ThisWorkbook.Worksheets("Ark2").Range("B12:B100").Value
ThisWorkbook.Worksheets("Ark1").Range("C1:C100").Value = ThisWorkbook.Worksheets("Ark2").Range("C12:C100").Value
ThisWorkbook.Worksheets("Ark1").Range("E1:E100").Value = ThisWorkbook.Worksheets("Ark2").Range("E12:E100").Value
ThisWorkbook.Worksheets("Ark1").Range("G1:G100").Value = ThisWorkbook.Worksheets("Ark2").Range("M12:M100").Value
ThisWorkbook.Worksheets("Ark1").Range("F1:F100").Value = ThisWorkbook.Worksheets("Ark2").Range("N12:N100").Value
ThisWorkbook.Worksheets("Ark1").Range("H1:H100").Value = ThisWorkbook.Worksheets("Ark2").Range("O12:O100").Value
If Worksheets("Ark1").Range("A4").Offset(1, 0) <> "" Then
Worksheets("Ark1").Range("A4").End(xlDown).Select
End If
ActiveCell.Offset(1, 0).Select
ActiveCell.Value = nøgletal
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = år
Worksheets("Ark2").Select
Worksheets("Ark2").Range("B2", "B16").Select
End Sub
Sub x()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 3
lngDataRows = 15
For t = 1 To lngDataRows
Range("l2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("f1:h1").Value)
Range("M2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("f1:h1").Offset(t).Value)
Next t
End Sub
A Special Transpose Vol. 2
Adjust the values in the constants section to fit your needs.
The first data row in Range1 (A2:C2) has to have values.
The Code
Sub TransposeAH()
Const cSheet1 As Variant = "Ark1" ' Sheet1 Name/Index
Const cSheet2 As Variant = "Ark1" ' Sheet2 Name/Index
Const cFirst As Integer = 2 ' First Row Number
Const cCol1First As Variant = "A" ' Range1 First Column Letter/Number
Const cCol1Last As Variant = "C" ' Range1 Last Column Letter/Number
Const cCol2First As Variant = "F" ' Range2 First Column Letter/Number
Const cCol2Last As Variant = "H" ' Range2 Last Column Letter/Number
Const cColumns As Integer = 2 ' Number of New Columns
Const cFirstCell As String = "L1" ' Target Range First Cell Address
Dim vntH As Variant ' Range2 Headers
Dim vnt2 As Variant ' Range2 Array
Dim vnt3 As Variant ' Range1 Temp Array (if value is "")
Dim vnt1 As Variant ' Range1 Array
Dim vntT As Variant ' Target Array
Dim LastUR As Long ' Last Used Row
Dim i As Long ' Arrays Row Counter
Dim j As Integer ' Arrays Column Counter
Dim k As Long ' Target Array Rows Counter
Dim m As Integer ' Range1 Temp Array Column Counter
' From Sheet1 to Arrays.
With Worksheets(cSheet1)
' Calculate Last Used Row.
With .Range(.Cells(cFirst, cCol1First), .Cells(.Rows.Count, cCol2Last))
If .Find("*", .Cells(.Rows.Count, .Columns.Count), -4123, , 1) _
Is Nothing Then Exit Sub
LastUR = .Find("*", , , , , 2).Row
End With
' Paste ranges into arrays.
vnt1 = .Range(.Cells(cFirst, cCol1First), .Cells(LastUR, cCol1Last))
vnt2 = .Range(.Cells(cFirst, cCol2First), .Cells(LastUR, cCol2Last))
vntH = .Range(.Cells(cFirst - 1, cCol2First), _
.Cells(cFirst - 1, cCol2Last))
End With
' Resize Target Array.
ReDim vntT(1 To UBound(vnt2) * UBound(vnt2, 2), _
1 To cColumns + UBound(vnt1, 2))
' Write Range2 Array to Target Array.
For i = 1 To UBound(vnt2)
For j = 1 To UBound(vnt2, 2)
k = k + 1
vntT(k, 1) = vntH(1, j)
vntT(k, 2) = vnt2(i, j)
Next
Next
' Resize Range1 Temp Array (if value is "")
ReDim vnt3(1 To 1, 1 To UBound(vnt1, 2))
' Copy first line of Range1 Array to Range1 Temp Array.
For m = 1 To UBound(vnt3, 2)
vnt3(1, m) = vnt1(1, m)
Next
' Write Range1 Array to Target Array.
k = 0
For i = 1 To UBound(vnt1)
For j = 1 To UBound(vnt1, 2)
k = k + 1
For m = 1 To UBound(vnt2, 2)
If vnt1(i, m) <> "" Then
If vnt1(i, m) <> vnt3(1, m) Then
vnt3(1, m) = vnt1(i, m)
End If
End If
vntT(k, m + cColumns) = vnt3(1, m)
Next
Next
Next
' Paste Target Array into Target Range resized
' from Target Range First Cell Address.
With Worksheets(cSheet2).Range(cFirstCell)
.Resize(UBound(vntT), UBound(vntT, 2)) = vntT
End With
End Sub

Speeding Up VBA Code for If Then Statement with Formula

I currently have two if then VBA codes, that are running extremely slow for my large data set and am looking for ways to optimize and speed them up.
The first formula is looking in a range of cells in column J that have a value in column A, and if they are blank in J then entering in a formula that contains a user defined function.
The second code is looking to see if any of the values in column J end in a , and if they do then remove that comma. Any help would be greatly appreciated!
Sub FillEmpty()
Dim r As Range, LastRow As Long
LastRow = Cells(Rows.Count, 1).End(xlUp).row
For Each r In Range("J2:J" & LastRow)
If r.Text = "" Then r.FormulaR1C1 = _
"=IFERROR((IF(LEFT(RC[-9],6)=""master"", get_areas(RC[-7]), """")),"""")"
Next r
End Sub
Sub NoComma()
Dim c As Range
For Each c In Range("J:J")
With c
If Right(.Value, 1) = "," Then .Value = Left(.Value, Len(.Value) - 1)
End With
Next c
End Sub
Speedup: Arrays
1. Code
It is unbelievable that you do not need formulaR1C1 to get a formula into the range when pasting from the array into range. But it's working on my computer. To conclude, the same principle from the second code is applied on the first: Range into Array, Loop and Array into Range. It doesn't get faster than this. The other idea for the first code was to create a range union and then paste the formula in one go.
Sub FillEmpty()
Const cCol As Variant = "J" ' Column Letter/Number
Const cFirst As Long = 2 ' First Row
Dim vntFE As Variant ' Range Array
Dim i As Long ' Range Array Rows Counter
' Paste range into array.
vntFE = Cells(cFirst, cCol).Resize(Cells(Rows.Count, cCol) _
.End(xlUp).Row - cFirst + 1)
' Loop through array and perform calculation.
For i = 1 To UBound(vntFE)
If vntFE(i, 1) = "" Then vntFE(i, 1) = "=IFERROR((IF(LEFT(RC[-9],6)" _
& "=""master"", get_areas(RC[-7]), """")),"""")"
Next
' Paste array into range.
Cells(cFirst, cCol).Resize(Cells(Rows.Count, cCol) _
.End(xlUp).Row - cFirst + 1) = vntFE
End Sub
Sub FillEmptyEasy()
Const cCol As Variant = "J" ' Column Letter/Number
Const cFirst As Long = 2 ' First Row
Dim rng As Range ' Range
Dim vntFE As Variant ' Range Array
Dim LastRow As Long ' Last Row
Dim i As Long ' Range Array Rows Counter
' Calculate Last Row.
LastRow = Cells(Rows.Count, cCol).End(xlUp).Row
' Calculate Range.
Set rng = Cells(cFirst, cCol).Resize(LastRow - cFirst + 1)
' Paste range into array.
vntFE = rng
' Loop through array and perform calculation.
For i = 1 To UBound(vntFE)
If vntFE(i, 1) = "" Then vntFE(i, 1) = "=IFERROR((IF(LEFT(RC[-9],6)" _
& "=""master"", get_areas(RC[-7]), """")),"""")"
Next
' Paste array into range.
rng = vntFE
End Sub
2. Code
Sub NoComma()
Const cCol As Variant = "J" ' Column Letter/Number
Const cFirst As Long = 2 ' First Row
Dim vntNoC As Variant ' Range Array
Dim i As Long ' Range Array Rows Counter
' Paste range into array.
vntNoC = Cells(cFirst, cCol).Resize(Cells(Rows.Count, cCol) _
.End(xlUp).Row - cFirst + 1)
' Loop through array and perform calculation.
For i = 1 To UBound(vntNoC)
If Right(vntNoC(i, 1), 1) = "," Then _
vntNoC(i, 1) = Left(vntNoC(i, 1), Len(vntNoC(i, 1)) - 1)
Next
' Paste array into range.
Cells(cFirst, cCol).Resize(Cells(Rows.Count, cCol) _
.End(xlUp).Row - cFirst + 1) = vntNoC
End Sub
Sub NoCommaEasy()
Const cCol As Variant = "J" ' Column Letter/Number
Const cFirst As Long = 2 ' First Row
Dim rng As Range ' Range
Dim vntNoC As Variant ' Range Array
Dim lastrow As Long ' Last Row
Dim i As Long ' Range Array Rows Counter
' Calculate Last Row.
lastrow = Cells(Rows.Count, cCol).End(xlUp).Row
' Calculate Range.
Set rng = Cells(cFirst, cCol).Resize(lastrow - cFirst + 1)
' Paste range into array.
vntNoC = rng
' Loop through array and perform calculation.
For i = 1 To UBound(vntNoC)
If Right(vntNoC(i, 1), 1) = "," Then _
vntNoC(i, 1) = Left(vntNoC(i, 1), Len(vntNoC(i, 1)) - 1)
Next
' Paste array into range.
rng = vntNoC
End Sub

Resources