Sub JonAgain() ' http://www.excelforum.com/excel-programming-vba-macros/1138627-dividing-the-items-of-an-array-over-multiple-columns.html
' Worksheets info.
Dim ws As Worksheet ' ' Preparing a "Pointer" to an Initial "Blue Print" in Memory of the Object ( Pigeon Hole with a bit of paper or code lines on that can be filled in to refer to a specific Objec of this type ) . This also us to get easily at the Methods and Properties throught the applying of a period ( .Dot) ( intellisense )
Set ws = ThisWorkbook.Worksheets("pgcArraysSplitToColumn") '( For Code in This Workbook ) '' Values are filled at the memory locations and the directions there are specified in the variable "Blue Print "Pointer""
Set ws = Worksheets("pgcArraysSplitToColumn") 'CHANGE TO SUIT YOUR SHEET (Refers here through Worksheets collection of open files )
' Determine Last Column Number( Two typical methods ) and the last Row. ' ' http://www.mrexcel.com/forum/excel-questions/48638-macro-needs-select-last-column.html#post223306 http://www.mrexcel.com/forum/excel-questions/48638-macro-needs-select-last-column.html
Dim lc As Long ' ' ' 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 lc = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column 'The Find Method looks for anything, searching by columns, starting at the first Cell and going backwards, which effectivelly starts at the last column which allows for different XL versions. This will determine the column that has anything in any row rather than looking in a particular row as in the above line.
Let lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column ' ' The Range Object ( cell ) that is the last cell in the row ( 1 here ) of interest, ( Column Number given by .Count Property applied to ( ws here, any would do, so wc can be ommited and the default for the macro is will be used ) Spreadsheet Range Columns Property) has the Property .End ( argument "Looking to left" ) appled to it. This Returns a new Range ( cell ) object which is that of the first Range ( cell ) with something in it "looking back to the left" in the XL spreadsheet from that last cell. Then the .Column Property is applied to return a long number equal to the Column number of that cell
Let lc = 9 'Hard copy alternative if you know it
Dim arrIn() As Variant 'We use the .Value Property below which when returne to a range bigger than 1 cell returns an Field of Variant Element Types, so we must Dimension approriately. Also the Array must be dynamic to allow that assignment
Let arrIn() = ws.Range("A1", ws.Cells(1, lc)).Value 'Note This becomes 1 2 D 1 column Array
'ws.Columns(50).ClearContents ' Remove any data already there, Just to be sure the next lines do any thing
'The width you want of the Output Array
Dim Widf As Long: Let Widf = 3
' Hard copied Indicies for Output Array
Dim rws() As Variant, clms() As Variant 'Variant Elements chosen for these Arrays to match type of Elements returned by the methods we use below
Let rws() = Array(1, 1, 1, 2, 2, 2, 3, 3, 3) 'Note this is 0 - 8 base 0
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
'Making those more flexible:
Dim strlClm As String 'Last column as Letter
Let strlClm = shgMathsVBASHimpfGlified(lc)
Let rws() = Evaluate("if(column(A:" & strlClm & "),int((column(A:" & strlClm & ")+(" & Widf & "-1))/" & Widf & "))")
Let clms() = Evaluate("If(column(A:" & strlClm & "),(mod((column(A:" & strlClm & ")-1)," & Widf & "))+1)") 'Note these are 1 - 9 base 1
'Make output Array using those Indicies
Dim arrout() As String 'We filll by looping and know type so can Dimension appropriately. We also know the size, so a Static 8 fixed size ) Array would be OK, but Dim only takes actual numbers, so we use below the ReDim which allows variables to be used
ReDim arrout(1 To (lc / Widf), 1 To Widf) 'make Approprately sized Array
Dim Cnt As Long 'Loop Bound Variable Count
For Cnt = 1 To lc 'Doing for all Input and output values
arrout(rws(Cnt), clms(Cnt)) = arrIn(1, Cnt) 'Go along each indice pair and put in the next Input Array value
Next Cnt
'Now paste Out to any Range starting at Top Left of
Dim TL As Range: Set TL = ws.Range("A40")
TL.Resize(UBound(arrout(), 1), UBound(arrout(), 2)).ClearContents 'Just to make sure the next line does something!
Let TL.Resize(UBound(arrout(), 1), UBound(arrout(), 2)).Value = arrout() ' Neat simple way to paste out the Values of an Array to a spreadsheet. The Top Left cell of where the Output should go has the .Resize Property applied whichreturns a new range Object of increased size. In this case we increase the dimension to the dimensions of the Output Array. Then the Allowed VBA one liner assighnment is used to assign the values of an Array to a Spreadsheet Range
End Sub
Public Function shgMathsVBASHimpfGlified(ByVal lClm As Long) As String ' http://www.excelforum.com/tips-and-tutorials/1108643-vba-column-letter-from-column-number-explained.html#post4221359
Let shgMathsVBASHimpfGlified = 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), "")
End Function
It will take for example this
Sub JonAgainSHimpfGlified()
Dim arrIn() As Variant: arrIn() = Range("A1:I1").Value
Dim Widf As Long, lc As Long: Widf = 3: lc = 9
Dim arrout() As Variant
ReDim arrout(1 To (lc / Widf), 1 To Widf)
Dim Cnt As Long
For Cnt = 1 To lc
arrout(Evaluate("if(column(A:" & shgMathsVBASHimpfGlified(lc) & "),int((column(A:" & shgMathsVBASHimpfGlified(lc) & ")+(" & Widf & "-1))/" & Widf & "))")(Cnt), Evaluate("If(column(A:" & shgMathsVBASHimpfGlified(lc) & "),(mod((column(A:" & shgMathsVBASHimpfGlified(lc) & ")-1)," & Widf & "))+1)")(Cnt)) = arrIn(1, Cnt)
Next Cnt
Range("A40").Resize(UBound(arrout(), 1), UBound(arrout(), 2)).ClearContents
Let Range("A40").Resize(UBound(arrout(), 1), UBound(arrout(), 2)).Value = arrout()
End Sub
Bookmarks