10
$\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$
2
  • $\begingroup$ related: 41362 $\endgroup$
    – Kuba
    Jan 30, 2015 at 11:11
  • 1
    $\begingroup$ Oddly enough, I encountered this same need yesterday. Went with the Reverse and Diagonal approach. $\endgroup$ Jan 31, 2015 at 21:31

7 Answers 7

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$
0
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$
1
  • $\begingroup$ It makes my head hurt trying to follow this. Mission accomplished I guess so +1. :-p $\endgroup$
    – Mr.Wizard
    Jan 31, 2015 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 and acknowledge you have read our privacy policy.

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