How to make dynamic column range for splitting string on comma - excel

I'm trying to create a macro that will go into a workbook, find cells that have a comma in them, split them and paste them starting at the last row in that column. The code below somewhat works but
It's limited in terms of changing the column range every time (a,b,c,etc). How do I dynamic, meaning run on multiple columns regardless of wherever the data starts?
Only start after the first row since I have headers.
The actual code below is a bit slow, what can I do to have it run more efficiently?
Sub LoopRange()
Dim rCell As Range
Dim rRng As Range
Dim myarray As Variant
Set rRng = Sheet1.Range("A:A")
For Each rCell In rRng
If InStr(1, rCell, ",") > 0 Then
myarray = Split(rCell, ",")
For i = 0 To UBound(myarray)
Range("A" & Rows.Count).End(xlUp).Offset(1).Value = myarray(i)
Next
Else
End If
Next
End Sub

Split Cell Values
Option Explicit
Sub GetSplitsTEST()
' The number of empty rows between the source (initial) data
' and the destination (resulting) data.
Const EmptyRows As Long = 0
Const Delimiter As String = ","
' Create a reference to the range.
Dim rg As Range
With Sheet1.Range("A1").CurrentRegion
'Debug.Print .Address ' with headers
Set rg = .Resize(.Rows.Count - 1).Offset(1)
'Debug.Print rg.Address ' without headers
End With
' Use the 'GetSplits' function to get the result in an array.
Dim Data As Variant: Data = GetSplits(rg, Delimiter)
' Validate the array.
If Not IsEmpty(Data) Then
' Write the result below the range.
rg.Cells(1).Offset(rg.Rows.Count + EmptyRows) _
.Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
End If
End Sub
Function GetSplits( _
ByVal rg As Range, _
Optional ByVal Delimiter As String = ",") _
As Variant
If rg Is Nothing Then Exit Function
Dim rCount As Long: rCount = rg.Rows.Count
Dim cCount As Long: cCount = rg.Columns.Count
Dim sData As Variant
If rCount = 1 And cCount = 1 Then
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = rg.Value
Else
sData = rg.Value
End If
Dim cDat As Variant: ReDim cDat(1 To cCount, 1 To 3)
Dim rDat As Variant: ReDim rDat(1 To rCount)
Dim c As Long, sr As Long, n As Long, drCount As Long, maxCount As Long
For c = 1 To cCount
drCount = 0
cDat(c, 1) = rDat
cDat(c, 2) = rDat
n = 0
For sr = 1 To rCount
If InStr(1, sData(sr, c), Delimiter) > 0 Then
n = n + 1
cDat(c, 1)(n) = Split(sData(sr, c), Delimiter)
cDat(c, 2)(n) = UBound(cDat(c, 1)(n))
drCount = drCount + cDat(c, 2)(n) + 1
End If
Next sr
cDat(c, 3) = n
If drCount > maxCount Then
maxCount = drCount
End If
Next c
Dim dData As Variant: ReDim dData(1 To maxCount, 1 To cCount)
Dim dr As Long
For c = 1 To cCount
dr = 0
For n = 1 To cDat(c, 3)
For sr = 0 To cDat(c, 2)(n)
dr = dr + 1
dData(dr, c) = cDat(c, 1)(n)(sr)
Next sr
Next n
Next c
GetSplits = dData
End Function

Related

Looping through rows in excel not sure how to assign a counter to go into different rows

Good morning,
I have a table with values that increment in the rows from left to right and then they change again as soon as I go down further
I wanted to loop through the rows and set the values in these rows in a different sheet to go in column A from row 2 and then it increments from A2 --> A3 --> A4...etc.
Sub LoopthroughRows ()
LastRow = Range("O" & Rows.Count).End(xlUp).Row
FirstRow = 2
i = FirstRow
FirstColumn = 15
Do Until i > LastRow
LastColumn = Cells(i, Columns.Count).End(xlToLeft).Column
Count = FirstColumn
k = 2
Do Until Count > LastColumn
Set Worksheets(Sheet7).Range("A" & k).Value = Worksheets(Sheet5).Range(Chr(Count + 64) & i).Value
Count = Count + 1
Loop
k=k+1
i=i+1
Loop
End Sub
when I run the code it comes up with Run time error '13' type mismatch. I tested the run through rows function and it works. I believe the issue might be with the set function in my Do loop?
Please help! I am using this to convert the rows into 1 column.
Thank you and have a great week :)
Get Column From Range
A Quick Fix: Practicing Do Loops (Slow)
Sub LoopthroughRows()
Dim fCell As Range: Set fCell = Sheet5.Range("O2")
Dim FirstRow As Long: FirstRow = fCell.Row
Dim FirstColumn As Long: FirstColumn = fCell.Column
Dim LastRow As Long
LastRow = Sheet5.Cells(Sheet5.Rows.Count, FirstColumn).End(xlUp).Row
Dim sr As Long: sr = FirstRow
Dim dr As Long: dr = 2
Dim LastColumn As Long
Dim sc As Long
Do Until sr > LastRow
sc = FirstColumn
LastColumn = Sheet5.Cells(sr, Sheet5.Columns.Count).End(xlToLeft).Column
Do Until sc > LastColumn
Sheet7.Cells(dr, "A").Value = Sheet5.Cells(sr, sc).Value
sc = sc + 1
dr = dr + 1
Loop
sr = sr + 1
Loop
End Sub
An Improvement: Using a Function (Fast)
Sub GetColumnFromRangeTEST()
Dim sfCell As Range: Set sfCell = Sheet5.Range("O2")
Dim srg As Range
With sfCell.CurrentRegion
Set srg = sfCell.Resize(.Row + .Rows.Count - sfCell.Row, _
.Column + .Columns.Count - sfCell.Column)
End With
Dim Data() As Variant
' Read by rows:
Data = GetColumnFromRange(srg)
' Read by columns:
'Data = GetColumnFromRange(srg, True)
Dim dfCell As Range: Set dfCell = Sheet7.Range("A2")
Dim drg As Range: Set drg = dfCell.Resize(UBound(Data, 1))
drg.Value = Data
End Sub
Function GetColumnFromRange( _
ByVal rg As Range, _
Optional ByVal ReadByColumns As Boolean = False) _
As Variant()
Dim srCount As Long: srCount = rg.Rows.Count
Dim scCount As Long: scCount = rg.Columns.Count
Dim drCount As Long: drCount = srCount * scCount
Dim sData() As Variant
If drCount = 1 Then
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = rg.Value
Else
sData = rg.Value
End If
Dim dData() As Variant: ReDim dData(1 To drCount, 1 To 1)
Dim sr As Long, sc As Long, dr As Long
If ReadByColumns Then
For sc = 1 To scCount
For sr = 1 To srCount
dr = dr + 1
dData(dr, 1) = sData(sr, sc)
Next sr
Next sc
Else
For sr = 1 To srCount
For sc = 1 To scCount
dr = dr + 1
dData(dr, 1) = sData(sr, sc)
Next sc
Next sr
End If
GetColumnFromRange = dData
End Function
If this is a simply swap of rows/columns, you can do this without looping:
Sub test()
With Sheets(1)
Dim sourceRng As Range: Set sourceRng = .Range(.Cells(1, 1), .Cells(4, 2))
.Cells(6, 6).Resize(sourceRng.Columns.Count, sourceRng.Rows.Count).Value = Application.Transpose(sourceRng)
End With
End Sub
Note that I use sourceRng.Columns.Count in the "row" place and sourceRng.Rows.Count in the "column" place for the resize.
Edit1:
Modifying to indicate how to utilize as a loop (untested):
Sub test()
With Sheets(1)
Dim i as Long
For i = firstRowSource to lastRowSource
Dim sourceRng As Range: Set sourceRng = .Range(.Cells(i, 1), .Cells(i, 2))
Dim targetColDest as Long: targetColDest = targetColDest + 1
.Cells(1, targetColDest ).Resize(sourceRng.Columns.Count,).Value = Application.Transpose(sourceRng)
Next i
End With
End Sub
This code converts rows to the one long column (values from 0 to 319)
Sub LoopthroughRows()
With ThisWorkbook
a = .Sheets(1).Range("O2").CurrentRegion
ReDim b(UBound(a, 1) * UBound(a, 2))
i = 0
For r = 1 To UBound(a, 1)
For c = 1 To UBound(a, 2)
b(i) = a(r, c)
i = i + 1
Next
Next
.Sheets(2).Range("A2").Resize(UBound(b)) = WorksheetFunction.Transpose(b)
End With
End Sub

Getting only the values base on a list

My code below gives me a result with a unique customer codes base on Calculation sheet. However, I want to get my result base on the list that I have in Solution Sheet. Also want to run the macro within Solution Sheet. Any help will be appreciated.
Calculation Sheet
Solution Sheet
Sub cTotals()
Dim arr, arr2, arr3
Dim Calc As Worksheet: Set TS = Worksheets("Calculation")
Dim Sol As Worksheet: Set Sol = Worksheets("Solution")
Dim x As Long, i As Long, a As Long, c As Long, ct As Long
Dim GIVMM As Single, MSU As Double, Cases As Double
arr = Calc.Range("B2:H" & Cells(Rows.Count, 1).End(xlUp).Row)
arr2 = arr
With CreateObject("Scripting.Dictionary")
For x = LBound(arr) To UBound(arr)
If Not IsMissing(arr(x, 1)) Then .Item(arr(x, 1)) = 1
Next
arr = .Keys
End With
ReDim arr3(1 To UBound(arr) + 1, 1 To 7)
c = 1: ct = 1
For i = 0 To UBound(arr)
For a = 1 To UBound(arr2)
If arr2(a, 1) = arr(i) Then
arr3(i + 1, c) = arr(i)
arr3(i + 1, c + 1) = ct
ct = ct + 1
GIVMM = GIVMM + arr2(a, 5)
arr3(i + 1, c + 2) = GIVMM
MSU = MSU + arr2(a, 6)
arr3(i + 1, c + 3) = MSU
Cases = Cases + arr2(a, 7)
arr3(i + 1, c + 4) = Cases
End If
Next
ct = 1: GIVMM = 0: MSU = 0: Cases = 0
Next
Sol.Range("B6").Resize(UBound(arr3, 1), UBound(arr3, 2)) = arr3
End Sub
Using Data Structures (Array, Collection, Dictionary)
Option Explicit
Sub CalculateData()
' Define constants.
' Source
Const sName As String = "Calculation"
Const scCol As Long = 2
Dim sCols() As Variant: sCols = VBA.Array(4, 6, 7, 8)
' Destination
Const dName As String = "Solution"
Const dfRow As Long = 6
Const dcCol As Long = 2
Const dColumnOffset As Long = 1
Dim dOffsets() As Variant: dOffsets = VBA.Array(1, 2, 3, 4)
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook
' Write the values from the source range ('srg') to an array ('sData').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range("A1").CurrentRegion
Dim sData() As Variant: sData = srg.Value
Dim srCount As Long: srCount = srg.Rows.Count
' Write the unique source values to the 'keys' ('sString')
' of a dictionary ('sDict'). Its 'items' ('sDict(sString)') will hold
' a collection of all the (source) rows ('r') where the 'key' appeared.
Dim sDict As Object: Set sDict = CreateObject("Scripting.Dictionary")
sDict.CompareMode = vbTextCompare
Dim sString As String
Dim r As Long
For r = 2 To srCount
sString = CStr(sData(r, scCol))
If Len(sString) > 0 Then
If Not sDict.Exists(sString) Then
Set sDict(sString) = New Collection
End If
sDict(sString).Add r
End If
Next r
' Write the values from the destination lookup column range ('dlrg')
' to a 2D one-based (one-column) array ('dlData').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dcCol).End(xlUp).Row
Dim drCount As Long: drCount = dlRow - dfRow + 1
If drCount < 1 Then
MsgBox "No data in the destination column.", vbCritical
Exit Sub
End If
Dim dlrg As Range: Set dlrg = dws.Cells(dfRow, dcCol).Resize(drCount)
Dim dlData() As Variant
If drCount = 1 Then ' one cell
ReDim dlData(1 To 1, 1 To 1): dlData(1, 1) = dlrg.Value
Else ' multiple cells
dlData = dlrg.Value
End If
' Write the results to the destination array ('dData').
Dim cUpper As Long: cUpper = UBound(sCols)
Dim cCount As Long: cCount = cUpper + 1
Dim dData As Variant: ReDim dData(1 To drCount, 1 To cCount)
Dim dDict As Object: Set dDict = CreateObject("Scripting.Dictionary")
dDict.CompareMode = vbTextCompare
Dim sItem As Variant
Dim sValue As Variant
Dim dString As String
Dim c As Long
For r = 1 To drCount
dString = CStr(dlData(r, 1))
If Len(dString) > 0 Then
If sDict.Exists(dString) Then ' found in the dictionary
For Each sItem In sDict(dString) ' loop through the rows
For c = 0 To cUpper
If c = 0 Then ' unique count
sString = CStr(sData(sItem, sCols(c)))
dDict(sString) = Empty
Else ' sum
sValue = sData(sItem, sCols(c))
If VarType(sValue) = vbDouble Then ' is a number
dData(r, c + 1) = dData(r, c + 1) + sValue
'Else ' is not a number; do nothing
End If
End If
Next c
Next sItem
dData(r, 1) = dDict.Count
dDict.RemoveAll
' Else ' not found in the dictionary; do nothing
End If
' Else ' vbNullString ('""'); do nothing
End If
Next r
' Write the values from the destination array to the destination range.
With dws.Cells(dfRow, dcCol).Offset(, dColumnOffset)
.Resize(drCount, cCount).Value = dData
End With
' Inform.
MsgBox "Data calculated.", vbInformation
End Sub

Select all values in Row "B" and "C" and move 1 step up

My Intention:
I wanna select all values in Rows "B" and "C" and move these 1 and 2 steps up.
The Example for what I have:
A
B
C
AA
Two
AA
Three
Two
AA
Three
Two
Three
X
yy
CC
The Example for what I would: If in Column-A find "X" should YY and CC delet
A
B
C
AA
Two
Three
AA
Two
Three
AA
Two
Three
My Code:
Sub test()
ActiveSheet.Select
Range("B:B").Select Shift:=xlUp, CopyOrigin:=xlFormatFromLeftOrAbove
Range("C:C").Select Shift:=xlUp, CopyOrigin:=xlFormatFromLeftOrAbove
End Sub
I would be happy if somebody help me
Align Data
Option Explicit
Sub AlignData()
Const Cols As String = "A:C"
Const fRow As Long = 1
Const ExceptionsList As String = "XX" ' comma-separated, no spaces!
Const Gap As Long = 1 ' number of empty rows in-between
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
' Reference the source range.
Dim srg As Range
Dim srCount As Long
With ws.Rows(fRow).Columns(Cols).Resize(ws.Rows.Count - fRow + 1)
Dim lrCell As Range
Set lrCell = .Find("*", , xlFormulas, , xlByRows, xlPrevious)
If lrCell Is Nothing Then Exit Sub ' no data
srCount = lrCell.Row - fRow + 1
Set srg = .Resize(srCount)
End With
Dim cCount As Long: cCount = srg.Columns.Count
' 1 to hold each column array
' 2 to hold a collection of each column's matching values
Dim jArr As Variant: ReDim jArr(1 To cCount, 1 To 2)
Dim Exceptions() As String: Exceptions = Split(ExceptionsList, ",")
Dim crg As Range
Dim c As Long
Dim r As Long
Dim sValue As Variant
' Write the column arrays to the jagged array.
For c = 1 To cCount
jArr(c, 1) = srg.Columns(c).Value ' column arrays
Set jArr(c, 2) = New Collection ' to hold the matching values
Next c
' Use a dictionary to hold the indexes of (unwanted) exception matches.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim dStep As Long: dStep = Gap + 1
Dim dData As Variant
Dim drCount As Long
Dim dr As Long
Dim sr As Long
For c = 1 To cCount
dr = 0
For sr = 1 To srCount
sValue = jArr(c, 1)(sr, 1)
If Not IsEmpty(sValue) Then ' exclude empty values
dr = dr + 1
If c = 1 Then ' 1st array
If IsError(Application.Match(sValue, Exceptions, 0)) Then
jArr(c, 2).Add sValue
Else ' found in exceptions
dict(dr) = Empty ' add the index
End If
Else ' all but the 1st array
If Not dict.Exists(dr) Then
jArr(c, 2).Add sValue
End If
End If
End If
Next sr
' Write the values from the collection to the destination array.
If c = 1 Then
drCount = jArr(c, 2).Count * dStep - 1
ReDim dData(1 To drCount, 1 To cCount)
End If
For sr = 1 To drCount Step dStep
dData(sr, c) = jArr(c, 2)(Int(sr / dStep) + 1)
Next sr
Set jArr(c, 2) = Nothing
Next c
' Write the values from the destination array to the range and clear below.
With srg.Resize(drCount)
.Value = dData
.Resize(ws.Rows.Count - .Row - drCount + 1).Offset(drCount).Clear
End With
End Sub
select all cells (A1:C5) and start the following macro
Sub FillCells()
Dim rngCell As Range
Do Until Application.WorksheetFunction.CountBlank(Selection) = 0
For Each rngCell In Selection
If rngCell.Value = "" Then
rngCell.Value = rngCell.Offset(1, 0).Value
End If
Next rngCell
Loop
End Sub
Best regards
Bernd

How do I make an excel vba function that can handle vertical and horizontal ranges

I saw this: Excel VBA: Determine if range is horizontal or vertical
I have this function that joins text if it's vertical:
Function textjoiner(x As Range, Optional delimiter As String = ",") As String
Dim darray() As Variant
Dim darray2() As Variant
Dim counter As Long, i As Long
darray = x.value
counter = UBound(darray, 1)
ReDim darray2(1 To counter)
For i = 1 To counter
darray2(i) = darray(i, 1)
Next i
textjoiner = join(darray2, delimiter)
End Function
What's the easiest way to modify it so it doestn' matter if it's an 1xn or nx1 range of cells, it will concatenate anyway?
Function textjoiner(xRange As Range, Optional delimiter As String = ",") As String
Dim oRet As String
oRet = ""
'Ensure we are dealing with a nx1 or 1xn range
If xRange.Rows.Count = 1 Or xRange.Columns.Count = 1 Then
'Concatenate each value in Range and add delimter
For Each oValue In xRange
oRet = oRet & oValue & delimiter
Next
' Remove last delimiter
oRet = Left(oRet, Len(oRet) - Len(delimiter))
End If
textjoiner = oRet
End Function
Handle Ranges
The following will work for any contiguous (one-area) range.
ByColumns set to True will allow reading one column at a time (default is one row at a time).
Option Explicit
Function TextJoiner( _
ByVal rg As Range, _
Optional ByVal Delimiter As String = ",", _
Optional ByVal ByColumns As Boolean = False) _
As String
If rg Is Nothing Then Exit Function
Dim rCount As Long: rCount = rg.Rows.Count
Dim cCount As Long: cCount = rg.Columns.Count
Dim sData As Variant
If rCount + cCount = 2 Then
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = rg.Value
Else
sData = rg.Value
End If
Dim nCount As Long: nCount = rCount * cCount
Dim nData As Variant: ReDim nData(1 To nCount)
Dim cValue As Variant
Dim r As Long, c As Long, n As Long
If ByColumns Then
For c = 1 To cCount
For r = 1 To rCount
cValue = sData(r, c)
If Not IsError(cValue) Then
If Len(cValue) > 0 Then
n = n + 1
nData(n) = cValue
End If
End If
Next r
Next c
Else
For r = 1 To rCount
For c = 1 To cCount
cValue = sData(r, c)
If Not IsError(cValue) Then
If Len(cValue) > 0 Then
n = n + 1
nData(n) = cValue
End If
End If
Next c
Next r
End If
If n < nCount Then
ReDim Preserve nData(1 To n)
End If
TextJoiner = Join(nData, Delimiter)
End Function

How select columns in a table based on index from array in VBA?

I have a table ("horiz") with following values
and table ("data") that shows different values per column
I want to make a VBA code that will save table "data" as following.
Basically looking for a code, which can do it in the following way:
1)load "horiz" values as an array
2)load "data" as a range
3)delete all zero values from "horiz" array
4)save the "data" table with column indexes that follow the values from array "horiz"
I tried the following code, however, the saving part is not working properly and do not know how to delete zeros in 3) step (I read that something should be done with If condition and ReDim function)
Sub sample()
Dim DirArray As Variant
DirArray = Range("horiz").Value
Dim rng As Range
Set rng = Range("data")
Worksheets("Sheet1").Range("L1").Cells.Value = rng.Cells(, DirArray).Value
End Sub
Copy 'Selected' Columns
Option Explicit
Sub copySelectedColumns()
Dim srg As Range: Set srg = Range("horiz") ' Select Range
Dim cCount As Long: cCount = Application.CountIf(srg, ">0") ' Columns Count
Dim sData As Variant: sData = srg.Value ' Select Data (Array)
Dim Data As Variant: Data = Range("data").Value ' Data
Dim ColData As Variant: ReDim ColData(1 To cCount) ' Column Data (Array)
Dim n As Long, c As Long
For n = 1 To UBound(sData, 2)
If sData(1, n) > 0 Then
c = c + 1
ColData(c) = sData(1, n)
End If
Next n
Dim rCount As Long: rCount = UBound(Data, 1)
Dim Result As Variant: ReDim Result(1 To rCount, 1 To cCount) ' Result
Dim r As Long
For r = 1 To rCount
For c = 1 To cCount
Result(r, c) = Data(r, ColData(c))
Next c
Next r
Worksheets("Sheet1").Range("L1").Resize(rCount, cCount).Value = Result
End Sub
EDIT
The improvement is about not allowing impossible columns (greater than the number of columns in the Data Range (0 was previously included)) and clearing the contents of a previous result.
The small range study is about writing the addresses of the four ranges to the Immediate window (CTRL+G).
An Improvement feat. a Small Range Study
Sub copySelectedColumns()
Debug.Print "***** The Ranges *****"
Dim srg As Range: Set srg = Range("horiz") ' Select Range
Debug.Print "Select Range: " & srg.Address(0, 0)
Dim sData As Variant: sData = srg.Value ' Select Data (Array)
Dim sCount As Long: sCount = UBound(sData, 2) ' Select Columns Count
Dim drg As Range: Set drg = Range("data") ' Data Range
Debug.Print "Data Range: " & drg.Address(0, 0)
Dim Data As Variant: Data = drg.Value ' Data
Dim dCount As Long: dCount = UBound(Data, 2) ' Data Columns Count
Dim ColData As Variant: ReDim ColData(1 To sCount) ' Column Data (Array)
Dim n As Long, c As Long
For n = 1 To sCount
If sData(1, n) > 0 And sData(1, n) <= dCount Then
c = c + 1
ColData(c) = sData(1, n)
End If
Next n
If c > 0 Then
Dim cCount As Long: cCount = c
Dim rCount As Long: rCount = UBound(Data, 1)
Dim Result As Variant: ReDim Result(1 To rCount, 1 To cCount) ' Result
Dim r As Long
For r = 1 To rCount
For c = 1 To cCount
Result(r, c) = Data(r, ColData(c))
Next c
Next r
With Worksheets("Sheet1").Range("L2")
' Clear contents of previous result.
Dim crg As Range ' Clear Range
Set crg = .Resize(.Worksheet.Rows.Count - .Row + 1, sCount)
Debug.Print "Clear Range: " & crg.Address(0, 0)
crg.ClearContents
' Write result.
Dim rrg As Range: Set rrg = .Resize(rCount, cCount) ' Result Range
Debug.Print "Result Range: " & rrg.Address(0, 0)
rrg.Value = Result
End With
Else
' all values in Select Range are invalid
' (0 or greater than Data Columns Count (dCount))
Debug.Print "The Select Range '" & srg.Address(0, 0) & "' contains " _
& "only invalid data."
End If
End Sub
Try:
Sub cut_paste_delete()
Dim ArrayHeader As Variant
Dim ArrayData As Variant
Dim FinalArray As Variant
Dim i As Long
Dim ZZ As Long
Dim vColumn As Long
ArrayHeader = Range("horiz").Value
ArrayData = Range("data").Value
i = Application.WorksheetFunction.CountIf(Range("horiz"), "<>0") 'how many valid columns
ReDim FinalArray(1 To UBound(ArrayData), 1 To i) As Variant
For i = 1 To 5 Step 1
If ArrayHeader(1, i) <> 0 Then
vColumn = vColumn + 1
For ZZ = 1 To UBound(ArrayData) Step 1
FinalArray(ZZ, vColumn) = ArrayData(ZZ, i)
Next ZZ
End If
Next i
'paste final array somewhere, in my case in P1
Range(Cells(1, 16), Cells(1 + ZZ - 2, 16 + vColumn - 1)).Value = FinalArray
Erase ArrayHeader, ArrayData, FinalArray
End Sub
The output i get afcter executing code:
Another approach could be
Sub CopyRg()
Dim rgKeep As Range
Dim rgData As Range
Dim rgResult As Range
Set rgKeep = Range("B2").CurrentRegion
Set rgData = Range("D7").CurrentRegion
Dim i As Long
i = 1
Dim sngColumn As Range
For Each sngColumn In rgData.Columns
If rgKeep.Columns(i).Value <> 0 Then
If rgResult Is Nothing Then
Set rgResult = sngColumn
Else
Set rgResult = Union(rgResult, sngColumn)
End If
End If
i = i + 1
Next sngColumn
rgResult.Copy
Range("B12").PasteSpecial
End Sub
with the following data (input and output)
The code does not transfer the data into arrays which could be slow for large datasets but on the other hands it only loops through the columns.

Resources