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}
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} *)
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}
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}
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
(* {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} *)
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} *)
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}
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} *)
Reverse
andDiagonal
approach. $\endgroup$