Sub Alanpgc() ' http://www.excelforum.com/excel-programming-vba-macros/1138428-multidimensional-array-to-single-column-range.html
' Worksheets info.
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("pgcArraysSplitToColumn")
Set ws = Worksheets("pgcArraysSplitToColumn") 'CHANGE TO SUIT YOUR SHEET
ws.Columns(50).ClearContents ' Remove any data already there, Just to be sure the next lines do any thing
Dim rngIn As Range, rngOut As Range
Set rngIn = ws.Range("F21:H23")
Set rngOut = ws.Range("AX1:AX9")
' Hard copied Indicies for rngIn in required series output.
Dim rws() As Variant, clms() As Variant 'Variant Elements chosen for these Arrays to match type of Elements returned by the mehtods we use below
Let rws() = Array(1, 1, 1, 2, 2, 2, 3, 3, 3)
Let clms() = Array(1, 2, 3, 1, 2, 3, 1, 2, 3)
' Some maths to get a more flexible solution
' Let rws() = Evaluate("int((column(A:I)+(3-1))/3))") ' The Maths is sound here, but you will only get the first value out of an internally made Array
' Let clms() = Evaluate("mod((column(A:I)-1),3))+1") ' You need to do a trick which stretches VBA to give out in your "Area" which would enclose all the values VBA has to offer http://www.mrexcel.com/forum/excel-questions/806702-visual-basic-applications-evaluate-range-vlookup.html?#post3944034
Let rws() = Evaluate("if(column(A:I),int((column(A:I)+(3-1))/3))") ' if(column(A:I),_______) is one.....
Let clms() = Evaluate("If(column(A:I),(mod((column(A:I)-1),3))+1)") '..... Trick to return an Array of all VBA has to offer for us in this case
' We Get a 1 D Range ( "Horizontal ) using .Index which will "paired" each consequtive indicie for "row" , "column" arguments which are Arrays of indicies, and give out consequtively in an "internal" 1 D Array
Dim rng1D As Range: Set rng1D = Range("AX1:BF1")
rng1D.ClearContents ' Remove any data already there, Just to be sure the next lines do any thing
Let rng1D.Value = Application.Index(rngIn, rws(), clms()) 'Returns a 1 D range, like a special 1 D Array ( Note just values here ) ... http://www.excelforum.com/showthread.php?t=1105617&page=2&p=4380627&highlight=#post4380627
' We want transpose of our 1 D " horizontal" "row"
Let rngOut.Value = Application.Transpose(rng1D)
' To make more flexible we rewite to work on Cells as the Input range, and deternmine our Columns a bit easier. ( And miss out the 1 D range bit )
'New indicies for Cells as Input Range
Let rws() = Array(21, 21, 21, 22, 22, 22, 23, 23, 23)
Let clms() = Array(6, 7, 8, 6, 7, 8, 6, 7, 8)
' Dim vTemp() As Variant: Let vTemp() = Application.Index(Cells, rws(), clms()): Let rngOut.Value = Application.Transpose(vTemp)
rng1D.ClearContents: rngOut.ClearContents ' Remove any data already there, Just to be sure the next lines do any thing
Let rngOut.Value = Application.Transpose(Application.Index(ws.Cells, rws(), clms())) 'This hard copied version works so...
'...Try to make it more flexible
Dim TLrw As Long, TLclm As Long, lrws As Long, lclms As Long ' Input range Top Left rows an columns and count of rows and columns Long is very simple to handle, - final memory "size" type is known (123.456 and 000.001 have same "size" computer memory ) , and so a Address suggestion can be given for the next line when the variable is filled in. ( Long is a Big whole Number limit (-2,147,483,648 to 2,147,483,647) If you need some sort of validation the value should only be within the range of a Byte/Integer otherwise there's no point using anything but Long.--upon/after 32-bit, Integers (Short) need converted internally anyways, so a Long is actually faster. ).
Let TLrw = rngIn.Row: Let TLclm = rngIn.Column: Let lclms = rngIn.Columns.Count: Let lrws = rngIn.Rows.Count
Dim CntCells As Long: CntCells = lrws * lclms ' Number of cells
Let rws() = Evaluate("if(column(A:I),int((column(A:I)+(3-1))/3))") 'Original based on Range to be used as first argument in Index
Let rws() = Evaluate("if(column(A:I),(int((column(A:I)+(3-1))/3))+(21-1))")
Let rws() = Evaluate("if(column(A:I),(int((column(A:I)+(3-1))/3))+(" & TLrw & "-1))")
Let rws() = Evaluate("if(column(A:I),(int((column(A:I)+(" & lclms & "-1))/" & lclms & "))+(" & TLrw & "-1))")
Let rws() = Evaluate("if(column(A:I),(int((column(A:I)+(" & lclms & "-1))/" & lclms & "))+(" & TLrw & "-1))")
Dim requiredColumnLetter As String: Let requiredColumnLetter = shgMathsVBA(CntCells)
Let requiredColumnLetter = shgMathsVBA(lrws * lclms)
Let requiredColumnLetter = shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count)
Let rws() = Evaluate("if(column(A:" & requiredColumnLetter & "),(int((column(A:" & requiredColumnLetter & ")+(" & lclms & "-1))/" & lclms & "))+(" & TLrw & "-1))")
Let rws() = Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),(int((column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")+(" & lclms & "-1))/" & lclms & "))+(" & TLrw & "-1))")
Let rws() = Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),(int((column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")+(" & rngIn.Columns.Count & "-1))/" & rngIn.Columns.Count & "))+(" & TLrw & "-1))")
Let rws() = Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),(int((column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")+(" & rngIn.Columns.Count & "-1))/" & rngIn.Columns.Count & "))+(" & rngIn.Row & "-1))")
Let clms() = Evaluate("If(column(A:I),(mod((column(A:I)-1),3))+1)") 'Original based on Range to be used as first argument in Index
Let clms() = Evaluate("if(column(A:I),mod(column(A:I)-1,3)+1+(6-1))")
Let clms() = Evaluate("if(column(A:I),mod(column(A:I)-1,3)+1+(" & TLclm & "-1))")
Let clms() = Evaluate("if(column(A:I),mod(column(A:I)-1,3)+" & TLclm & ")")
' Dim requiredColumnLetter As String: Let requiredColumnLetter = shgMathsVBA(CntCells)
Let clms() = Evaluate("if(column(A:" & requiredColumnLetter & "),mod(column(A:" & requiredColumnLetter & ")-1,3)+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(CntCells) & "),mod(column(A:" & shgMathsVBA(CntCells) & ")-1,3)+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(CntCells) & "),mod(column(A:" & shgMathsVBA(CntCells) & ")-1," & lclms & ")+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(CntCells) & "),mod(column(A:" & shgMathsVBA(CntCells) & ")-1," & lclms & ")+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(lrws * lclms) & "),mod(column(A:" & shgMathsVBA(lrws * lclms) & ")-1," & lclms & ")+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(lrws * rngIn.Columns.Count) & "),mod(column(A:" & shgMathsVBA(lrws * rngIn.Columns.Count) & ")-1," & rngIn.Columns.Count & ")+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),mod(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")-1," & rngIn.Columns.Count & ")+" & TLclm & ")")
Let clms() = Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),mod(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")-1," & rngIn.Columns.Count & ")+" & rngIn.Column & ")")
rng1D.ClearContents: rngOut.ClearContents ' Remove any data already there, Just to be sure the next lines do any thing
Let rngOut.Value = Application.Transpose(Application.Index(ws.Cells, rws(), clms()))
Let rngOut.Value = Application.Transpose(Application.Index(ws.Cells, Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),(int((column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")+(" & rngIn.Columns.Count & "-1))/" & rngIn.Columns.Count & "))+(" & rngIn.Row & "-1))"), Evaluate("if(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & "),mod(column(A:" & shgMathsVBA(rngIn.Rows.Count * rngIn.Columns.Count) & ")-1," & rngIn.Columns.Count & ")+" & rngIn.Column & ")")))
End Sub
Rem Ref pgc http://www.mrexcel.com/forum/excel-questions/908760-visual-basic-applications-copy-2-dimensional-array-into-1-dimensional-single-column-2.html
Function shgMathsVBA(ByVal lclm As Long) As String '
' Dim vtemp
' Let vtemp = IIf(((((lclm - 1) \ 26) - 1) \ 26) <> 0, Chr(65 + (((((lclm - 1) \ 26) - 1) \ 26) - 1 Mod 26)), "")
' Let vtemp = Evaluate("IF(QUOTIENT(QUOTIENT(" & lclm & "-1, 26)-1, 26), CHAR(MOD(QUOTIENT(QUOTIENT(" & lclm & "-1, 26)-1, 26), 26)-1 + 65), """") ")
' Let vtemp = IIf(((lclm - 1) \ 26) <> 0, Chr(65 + (((lclm - 1) \ 26) - 1) Mod 26), "")
' Let vtemp = Evaluate("IF(QUOTIENT(" & lclm & "-1, 26), CHAR(MOD(QUOTIENT(" & lclm & "-1, 26)-1, 26) + 65), """")")
' Let vtemp = IIf(lclm <> 0, Chr(65 + (lclm - 1) Mod 26), "")
' Let vtemp = Evaluate("IF(" & lclm & ", CHAR(MOD(" & lclm & "-1, 26) + 65), """") & """"")
' Let FucshgMathsVBA = IIf(((((lclm - 1) \ 26) - 1) \ 26) <> 0, Chr(65 + (((((lclm - 1) \ 26) - 1) \ 26) - 1 Mod 26)), "") & IIf(((lclm - 1) \ 26) <> 0, Chr(65 + (((lclm - 1) \ 26) - 1) Mod 26), "") & IIf(lclm <> 0, Chr(65 + (lclm - 1) Mod 26), "")
Let shgMathsVBA = IIf(((((lclm - 1) \ 26) - 1) \ 26), Chr(65 + (((((lclm - 1) \ 26) - 1) \ 26) - 1 Mod 26)), "") & IIf(((lclm - 1) \ 26), Chr(65 + (((lclm - 1) \ 26) - 1) Mod 26), "") & IIf(lclm, Chr(65 + (lclm - 1) Mod 26), "")
' Let FucshgMathsVBA = Evaluate("IF(QUOTIENT(QUOTIENT(" & lclm & "-1, 26)-1, 26), CHAR(MOD(QUOTIENT(QUOTIENT(" & lclm & "-1, 26)-1, 26)-1, 26) + 65), """") & IF(QUOTIENT(" & lclm & "-1, 26), CHAR(MOD(QUOTIENT(" & lclm & "-1, 26)-1, 26) + 65), """") & IF(" & lclm & ", CHAR(MOD(" & lclm & "-1, 26) + 65), """") & """"")
End Function
Rem Ref shg http://www.excelforum.com/tips-and-tutorials/1108643-vba-column-letter-from-column-number-explained.html#post4214733
Bookmarks