# How to select all elements above the main diagonal of matrix?

How to select all elements above the main diagonal of matrix? I need to create a list of them.

-

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]}

-
Niiiiice, I learned something new –  Rojo Jan 30 '14 at 1:49

Let's use Span with Part:

mat=RandomInteger[{0, 100}, {5, 5}];

Flatten[mat[[#, # + 1 ;;]] & /@ Range[5]]

-
Nice, clean, clever, and faster than the naive solution. +1 –  ciao Jan 30 '14 at 5:32

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 = DeveloperFromPackedArray @ 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.

-
Join is not only faster but better than flatten (with no second arg) if the matrix can have list elements –  Rojo Jan 30 '14 at 6:47
@Rojo Good point. –  Mr.Wizard Jan 30 '14 at 7:05
Nice tuning, as usual! For non-huge arrays, I use (filter matching this particular problem in this case): FilterRules[ArrayRules[yourArrayHere], {a_, b_} /; b > a] Just seems... neat, if not a hot-rod. –  ciao Jan 30 '14 at 7:53
@rasher You should post that ArrayRules method; it does have flair. –  Mr.Wizard Jan 30 '14 at 7:54
I don't know but I've ran this and upperElemets and aboveDiag have comparable timings for PackedArray. Also in packed case my Pick is two times faster, unless I'm doing something wrong. –  Kuba Jan 30 '14 at 8:35
n = 4;
mat = Array[a, {n, n}];

Flatten@Table[If[j > i, mat[[i, j]], {}], {i, n}, {j, n}]


-
I liked the replacing by {} for future flattening. +1 –  Rojo Jan 30 '14 at 2:09

Here's an option for square matrices using undocumented properties of SparseArray, which clocks in slightly faster for me than Mr.Wizard's solution:

upperElements[mat_?MatrixQ] := With[{n = Length@mat},
SparseArray[UpperTriangularize[mat, 1]]["NonzeroValues"] ~PadRight~ (n (n - 1)/2)];


This constructs a sparse strictly upper triangular matrix, extracts the non-zero values and then pads it to a length of $n(n-1)/2$, where $n$ is the dimension of the matrix (to account for any upper element that might have been zero).

For non-square matrices of dimension $m\times n$, you might try using a closed form expression for the number of upper triangular entries (see here, for instance).

-
How come I didn't think of padright and worried about deleting extra zeros. +1 –  Rojo Jan 30 '14 at 7:01
On my system (v7) this is about six to seven times slower than aboveDiag with n = 5000; mat = RandomInteger[999, {n, n}]; (and leaving out MatrixQ for a fair test). What data are you testing with, and what timings do you get for my data in v9? –  Mr.Wizard Jan 30 '14 at 7:04
@Mr.Wizard I don't have the timings right now, but it was very close to yours, but a wee bit faster. I see from the comments under yours that Kuba got similar results. I don't have v7 installed, so I can't confirm your findings. –  The Toad Jan 30 '14 at 16:55

n = 4;
m = Array[a, {n, n}];
Join @@ Table[m[[ i, j]], {i, n}, {j, i + 1, n}]

{a[1, 2], a[1, 3], a[1, 4], a[2, 3], a[2, 4], a[3, 4]}


just another way:

Join @@ Pick[
m,
UpperTriangularize[ConstantArray[1, {n, n}], 1],
1]

-
n = 4;
mat = Array[a, {n, n}];
mat[[##]] & @@@ Subsets[Range[n], {2}]
(* {a[1,2],a[1,3],a[1,4],a[2,3],a[2,4],a[3,4]} *)
`
-