How to select all elements above the main diagonal of matrix?
The Diagonal command has a second argument that allows listing the elements of the jth superdiagonal. So we can map over all the superdiagonals:
n = 4;
mat = Array[a, {n, n}];
Flatten[Diagonal[mat, #] & /@ Range[n-1]]
which gives a list of all the elements above the diagonal:
{a[1, 2], a[2, 3], a[3, 4], a[1, 3], a[2, 4], a[1, 4]}
Let's use Span
with Part
:
mat=RandomInteger[{0, 100}, {5, 5}];
Flatten[mat[[#, # + 1 ;;]] & /@ Range[5]]
I believe that kale's approach is the best, but it can be improved with Join
which is considerably faster than Flatten
on packed lists, and it is a bit cleaner when written with Array
:
Join @@ Array[mat[[#, # + 1 ;;]] &, n - 1]
To make this into a fast function it seems that one needs a Hold attribute (pass-by-reference):
SetAttributes[aboveDiag, HoldFirst];
aboveDiag[a_] := Join @@ Array[a[[#, # + 1 ;;]] &, Length[a] - 1]
Compare timings (done in v7) with bill s's code and R.M's upperElements
function. (I left MatrixQ
out of upperElements
in these tests to eliminate overhead and level the field.)
n = 5000;
mat = RandomInteger[999, {n, n}];
Flatten[Diagonal[mat, #] & /@ Range[n - 1]] // Timing // First
upperElements[mat] // Timing // First
aboveDiag[mat] // Timing // First
0.3276 0.1872 0.02308
Not quite as superior on non-packed data, but still a good bit faster than the others.
n = 2000;
mat = Developer`FromPackedArray @ RandomInteger[999, {n, n}];
Flatten[Diagonal[mat, #] & /@ Range[n - 1]] // Timing // First
upperElements[mat] // Timing // First
aboveDiag[mat] // Timing // First
0.1404 0.0998 0.02308
Inspired by rasher's use of MapIndexed
, here is another one that tests the fastest on unpacked data on my system (using last mat
above):
Join @@ MapIndexed[Drop[#, #2[[1]]] &, mat] // Timing // First
0.01996
It is much slower than aboveDiag
on packed data.