Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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

share|improve this question

7 Answers 7

up vote 8 down vote accepted

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]}
share|improve this answer
    
Niiiiice, I learned something new –  Rojo Jan 30 at 1:49

Let's use Span with Part:

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

Flatten[mat[[#, # + 1 ;;]] & /@ Range[5]]
share|improve this answer
    
Nice, clean, clever, and faster than the naive solution. +1 –  rasher Jan 30 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 = 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.

share|improve this answer
1  
Join is not only faster but better than flatten (with no second arg) if the matrix can have list elements –  Rojo Jan 30 at 6:47
    
@Rojo Good point. –  Mr.Wizard Jan 30 at 7:05
2  
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. –  rasher Jan 30 at 7:53
1  
@rasher You should post that ArrayRules method; it does have flair. –  Mr.Wizard Jan 30 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 at 8:35
n = 4;
mat = Array[a, {n, n}];

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

Mathematica graphics

share|improve this answer
    
I liked the replacing by {} for future flattening. +1 –  Rojo Jan 30 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).

share|improve this answer
    
How come I didn't think of padright and worried about deleting extra zeros. +1 –  Rojo Jan 30 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 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. –  rm -rf Jan 30 at 16:55

Variation of Nasser answer:

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]
share|improve this answer
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]} *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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