I'm looking to tile an Excel array in 2 dimensions, as defined by another array, ideally not using VBA.
To explain better, what I would like is an excel formula for f(A, B)
Where A is boolean and =
[[1, 0],
[0, 1]
Where B =
[[1, 2],
[3, 4]
And f(A, B)
tiles B according to bool values in A, in this case, f(A, B) =
[[1, 2, 0, 0],
[3, 4, 0, 0],
[0, 0, 1, 2],
[0, 0, 3, 4]]
My initial thoughts were of =IF(MUNIT(2), {1, 2;3, 4}, {0, 0;0, 0})
but the output does not expand well.
This is my effort so far - hopefully it's fairly general:
=LET(A,A1:B2,B,D1:E2,DROP(REDUCE(SEQUENCE(1,COLUMNS(A)*COLUMNS(B)),SEQUENCE(ROWS(A)),LAMBDA(rowAcc,row,VSTACK(rowAcc,
DROP(REDUCE(SEQUENCE(ROWS(B)),SEQUENCE(1,COLUMNS(A)),LAMBDA(colAcc,col,HSTACK(colAcc,B*INDEX(A,row,col)))),,1)))),1))
You could also use Makearray:
=LET(A,A1:B2,B,D1:E2,rA,ROWS(A),rB,ROWS(B),cA,COLUMNS(A),cB,COLUMNS(B),
MAKEARRAY(rA*rB,cA*cB,LAMBDA(r,c,INDEX(A,(r-1)/rB+1,(c-1)/cB+1)*INDEX(B,MOD(r-1,rB)+1,MOD(c-1,cB)+1))))
(Same logic as @Scott Craner's legacy version)
Here is some sample VBA code in case you wanted to go down that route:
Sub Kron()
Dim AR As Range, BR As Range, OutR As Range
' A is the boolean array, B is array to be tiled.
Dim A() As Variant
Dim B() As Variant
Dim aRows As Long, bRows As Long, aCols As Long, bCols As Long, outRows As Long, OutCols As Long
Dim aRow As Long, aCol As Long, bRow As Long, bCol As Long, outRow As Long, outCol As Long
Dim Out() As Integer
Set AR = Range("A1:C2")
Set BR = Range("D1:F3")
Set OutR = Range("Q1")
A = AR.Value
B = BR.Value
aRows = UBound(A, 1)
aCols = UBound(A, 2)
bRows = UBound(B, 1)
bCols = UBound(B, 2)
outRows = aRows * bRows
OutCols = aCols * bCols
ReDim Out(outRows, OutCols)
' Loop over boolean array A
outRow = 1
For aRow = 1 To aRows
outCol = 1
For aCol = 1 To aCols
' Only call Tile if A contains 1
If A(aRow, aCol) = 1 Then Call Tile(Out, B, outRow, outCol, bRows, bCols)
outCol = outCol + bCols
Next aCol
outRow = outRow + bRows
Next aRow
OutR.Resize(outRows, OutCols) = Out
End Sub
Private Sub Tile(Out, T, startRow, startCol, height, width)
Dim tileRow As Long
Dim tileCol As Long
Dim outRow As Long
Dim outCol As Long
'Loop over tiling array locally called T
outRow = startRow
For tileRow = 1 To height
outCol = startCol
For tileCol = 1 To width
Out(outRow, outCol) = T(tileRow, tileCol)
outCol = outCol + 1
Next tileCol
outRow = outRow + 1
Next tileRow
End Sub