9
$\begingroup$

I have a square matrix: {{1,2,3},{4,5,6},{7,8,9}} and I want to get a list:

{1,2,4,3,5,7}
$\endgroup$
  • $\begingroup$ related: 41362 $\endgroup$ – Kuba Jan 30 '15 at 11:11
  • 1
    $\begingroup$ Oddly enough, I encountered this same need yesterday. Went with the Reverse and Diagonal approach. $\endgroup$ – Daniel Lichtblau Jan 31 '15 at 21:31
12
$\begingroup$

A straightforward and clear solution:

f[m_] := Flatten@Table[m[[j, i - j + 1]], {i, Length@m}, {j, i}]

f@{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
(* {1, 2, 4, 3, 5, 7} *)

A fast compiled version:

fc = Compile[{{m, _Integer, 2}}, 
   Module[{n = Length@m, res, k = 0}, 
    res = Array[0 &, Quotient[n (n + 1), 2]]; 
    Do[res[[++k]] = m[[j, i - j + 1]], {i, Length@m}, {j, i}]; 
    res], CompilationTarget -> "C", RuntimeOptions -> "Speed"];

One can also write unobvious fast uncompiled solution:

f2[m_] := With[{n = Length@m}, Flatten[m][[# + (n - 1) Quotient[#2 - #^2 + #, 2]]] &[
     Round@Sqrt@N@#, #] &@Range[1, n^2 + n, 2]]

n = 1000;
m = RandomInteger[10, {n, n}];

fc[m] == f[m] == f2[m] == fm[m]
(* True *)

f[m]; // AbsoluteTiming
fc[m]; // AbsoluteTiming
f2[m]; // AbsoluteTiming
fm[m]; // AbsoluteTiming  (* ubpdqn *)
(* {1.263933, Null} *)
(* {0.035024, Null} *)
(* {0.118597, Null} *)
(* {0.310459, Null} *)
$\endgroup$
5
$\begingroup$
f[n_] := Join @@ (Thread[{Range[#], Range[#, 1, -1]}] & /@ 
     Range[n]);
fm[mat_] := Extract[mat, f[Length[mat]]]

So,

m = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
fm[m]

yields:{1, 2, 4, 3, 5, 7}

$\endgroup$
4
$\begingroup$
f = Function[m,
       Flatten[
         Diagonal[Reverse[m, {2}], #] & /@ Range[Length[m], 0, -1]
       ]
    ]

f @ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
{1, 2, 4, 3, 5, 7}
$\endgroup$
3
$\begingroup$

Purely (sic) for @Mr.Wizard's entertainment... ;D

f @ m_ :=
  m[[(#+#2-#3)/2,(2-#+#2+#3)/2]]&[#,#2,#2^2]&[#,Round@Sqrt@#]&[2#]& ~Array~
  (#(#+1)/2&@Length@m)

f @ {{1,2,3},{4,5,6},{7,8,9}}
(* {1,2,4,3,5,7} *)

m = Range[49] ~Partition~ 7;
m // MatrixForm
f @ m

matrix screenshot

(* {1,2,8,3,9,15,4,10,16,22,5,11,17,23,29,6,12,18,24,30,36,7,13,19,25,31,37,43} *)

(with thanks to a couple of entries in the OEIS)

$\endgroup$
  • $\begingroup$ It makes my head hurt trying to follow this. Mission accomplished I guess so +1. :-p $\endgroup$ – Mr.Wizard Jan 31 '15 at 11:45
2
$\begingroup$

another way. The idea is to take diagonal of each larger matrix. But need to rotate it by 90 degrees each time, hence the Reverse[Transpose@mat.

Flatten[(Diagonal@Reverse[Transpose@mat[[1;;#, 1;;#]]])& /@ Range[Length[mat]]]

    (* {1, 2, 4, 3, 5, 7} *)
$\endgroup$
2
$\begingroup$

Yet another just for fun:

m = {{1,2,3},{4,5,6},{7,8,9}};

m[[-#, # ;; 1 ;; -1]] & ~Array~ Length@m ~Flatten~ {{2, 1}} // Reverse
{1, 2, 4, 3, 5, 7}
$\endgroup$
1
$\begingroup$

Extract enables you to prep the indices in advance.

entries[A_?SquareMatrixQ] :=
 With[{indices = Flatten[
     Table[{i, j - i + 1}, {j, Length[A]}, {i, j}], 1]},
  Extract[A, indices]]

entries[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}]
(* {1, 2, 4, 3, 5, 7} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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