16
\$\begingroup\$

Inspired by Copied from this question at Stack Overflow.

Given a matrix A, create a matrix B such that the columns of A are arranged in a block-diagonal fashion. For example, given

1 2 3
4 5 6

the output would be

1 0 0
4 0 0
0 2 0
0 5 0
0 0 3
0 0 6

Rules

Input and output may be in the form of 2D arrays, nested arrays, or strings with different separators for rows and columns.

Numbers in the input (matrix A) will be positive integers.

Unary format is allowed, as long as zeros in the output are displayed in some reasonable way. For example, the above result could be displayed using quotation marks to enclose each number:

'1' '' ''
'1111' '' ''
'' '11' ''
'' '11111' ''
'' '' '111'
'' '' '111111'

Test cases

Input, output:

1 2 3
4 5 6

1 0 0
4 0 0
0 2 0
0 5 0
0 0 3
0 0 6


10 20

10  0
 0 20    


10
20

10
20


  1   2   3
 10  20  30
100 200 300

  1   0   0
 10   0   0
100   0   0
  0   2   0
  0  20   0
  0 200   0
  0   0   3
  0   0  30
  0   0 300

 2  4
 6  8
10 12

 2  0
 6  0
10  0
 0  4
 0  8
 0 12
\$\endgroup\$
2
  • \$\begingroup\$ Will all the numbers in A be different? \$\endgroup\$
    – Adám
    Feb 25, 2016 at 1:46
  • \$\begingroup\$ @Nᴮᶻ No, they can be equal \$\endgroup\$
    – Luis Mendo
    Feb 25, 2016 at 9:57

10 Answers 10

7
\$\begingroup\$

MATL, 6 bytes

"@N$Yd

Works in current version (13.0.0) of the language/compiler.

Input has the following form, with semicolon as row separator, and commas or spaces as column separators within each row:

[1, 2, 3; 4, 5, 6]

Try it online!

Explanation

"         % implicitly input 2D array and loop over its columns
  @       %   push column
  N$Yd    %   build block-diagonal matrix from all stack contents. Stack contents are
          %   a single column in the first iteration, or a partially built 2D array
          %   and a new column in all other iterations
          % end loop
          % implicit display

Worked example

Consider the input [1 2 3; 4 5 6]. The for loop beginning with " takes each column of the input. Within each iteration, @ pushes the current column onto the stack. So in the first iteration it pushes [1; 4]. N$ specifies that all the stack contents will be used as inputs of the following function, Yd.

This function (corresponding to MATLAB's blkdiag) "diagonally concatenates" its inputs to produce a block diagonal matrix (2D array). So in the first iteration Yd it takes one input and produces an output equal to that input, [1; 4], which is left on the stack.

In the second iteration the second column of the input, [2; 5], is pushed. Now Yd takes two 2×1 inputs, namely [1; 4] and [2; 5], and produces the 4×2 array [1 0; 4 0; 0 2; 0 5].

In the third iteration Yd takes the latter 4×2 array and the third column of the input, [3; 6], and produces the final result [1 0 0; 4 0 0; 0 2 0; 0 5 0; 0 0 3; 0 0 6].

\$\endgroup\$
3
\$\begingroup\$

ES6, 65 bytes

a=>[].concat(...a[0].map((_,i)=>a.map(b=>b.map((c,j)=>i-j?0:c))))

Takes as input and returns as output an array of arrays.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ @WashingtonGuedes The inner map returns a copy of the original 2D array with all but one column zeroed out. These copies then need to be concatenated, rather than just being elements of an outer 3D array. \$\endgroup\$
    – Neil
    Feb 23, 2016 at 16:48
3
\$\begingroup\$

Mathematica, 40 39 Bytes

Credit to @Seeq for Infixing Flatten.

Transpose[DiagonalMatrix/@#]~Flatten~1&

Input is a list of row vectors delimited by {} brackets. So the initial example is represented by

{{1,2,3},{4,5,6}}

Generate an array of DiagonalMatrix where each one has diagonal elements from the rows of the input (3-D array). Transpose so the Flatten operation removes the correct bracket pairs to give the desired matrix (now 2-D array).

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Wouldn't DiagonalMatrix/@# work? And, by extension, Transpose[DiagonalMatrix/@#]~Flatten~1& \$\endgroup\$
    – seequ
    Feb 23, 2016 at 20:28
  • \$\begingroup\$ Good catch, I intended to fix that after rolling it up. Didn't think to use the Infix Flatten though. +1. \$\endgroup\$
    – IPoiler
    Feb 23, 2016 at 21:49
2
\$\begingroup\$

Pyth, 17

s.em.>+dm0thQkbCQ

Try it online or run the Test Suite.

You can add a leading j to help visualize the 2D array.

\$\endgroup\$
1
\$\begingroup\$

Jelly, 13 bytes

ZLR’×L0ẋ;"Zz0

Try it online!

How it works

ZLR’×L0ẋ;"Zz0  Main link. Input: M (matrix)

Z              Transpose M.
 L             Get the length of the result. This yields the number of M's columns.
  R            Range; for m columns, yield [1, ..., m].
   ’           Decrement to yield [0, ..., m-1].
    ×L         Multiply each by the length (number of rows) of M.
               This yields [0, n, ..., n(m-1)], where n is the number of rows.
      0ẋ       Push a list of lists of zeroes.
               First element is [], last is n(m-1) zeroes.
        ;"Z    Prepend the kth vector of zeroes to the kth column of M.
           z0  Zip, filling the non-rectangular 2D array with zeroes.
\$\endgroup\$
1
\$\begingroup\$

Mathematica, 111 bytes

Join@@@ReplacePart[Table[0,#2/#3]~Table~#3~Table~#3,Table[{n,n}->#[[n]],{n,#3}]]&[Length@#,Length@Flatten@#,#]&
\$\endgroup\$
1
  • \$\begingroup\$ What's the input syntax? This throws Table and Part errors when using standard MMA matrix notation and results in an array of mixed dimensions. \$\endgroup\$
    – IPoiler
    Feb 23, 2016 at 18:41
1
\$\begingroup\$

Ruby, 81 78 76 62 bytes

->a{i=-1;a[0].flat_map{i+=1;a.map{|b|x=b.map{0};x[i]=b[i];x}}}

sigh Manually keeping track of the index is shorter than with_index.

->a{
i=-1;            # index of the flat_map
a[0]             # duplicate all rows as many times as necessary
.flat_map{       # we're wrapping each "group" of original rows with yet another
                 #  array, so we need to flat_map to get rid of those
i+=1;            # increment the index of the current subarray
a.map{|b|        # for each sub-subarray (these are the rows)...
x=b.map{0};      # zero everything out
x[i]=b[i];       # replace the desired elements
x}}}             # finally, return the modified array
\$\endgroup\$
1
\$\begingroup\$

R, 41 bytes

pryr::f(Matrix::.bdiag(plyr::alply(a,2)))

Assumes pryr, Matrix and plyr packages are installed.

This creates a function that takes a 2D array (a) and returns a "sparseMatrix" where (where 0's are represented as .)

(a=matrix(1:6,ncol=3))
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6
pryr::f(Matrix::.bdiag(plyr::alply(a,2)))(a)
# 6 x 3 sparse Matrix of class "dgTMatrix"
#          
# [1,] 1 . .
# [2,] 2 . .
# [3,] . 3 .
# [4,] . 4 .
# [5,] . . 5
# [6,] . . 6

Explanation:

plyr::alply(a,2) each column of a and returns combines these results in a list

Matrix::.bdiag(lst) creates a block diagonal matrix from a list of matrices

pryr::f is a shorthand way to create a function.

A fully base R solution in 59 bytes (using the logic of @PieCot's Matlab answer):

function(a){l=dim(a);diag(l[2])%x%matrix(1,nrow=l[1])*c(a)}
\$\endgroup\$
1
\$\begingroup\$

MATLAB, 69 68 bytes

   function h=d(a)
   [r,c]=size(a);h=repmat(a,c,1).*kron(eye(c),~~(1:r)')

One byte was shaved off: thanks to Luis Mendo :)

\$\endgroup\$
0
1
\$\begingroup\$

APL (Dyalog Classic), 11 bytes

⍉⍪⍉↑(0,⊢)\⎕

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.