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.

I asked this question before, but i was closed because it the question was not comprehensible enough. So i reworded it, hope that's ok.


I have a list with 6 elements.

{a1, a2, a3, a4, a5, a6}

Now, I want to generate a upper triangle matrix with the elements above as matrix elements, so that the matrix reads

{{a1, a4, a6}, {0, a2, a5}, {0, 0, a3}}

That is, the triangle upper matrix matrix shall be filled up with the elements of the list. It is not important where each element is placed.

I want to do this also with larger matrices, so for example a list with 36 elements shall form a 8 x 8 upper triangle matrix.

Any ideas?

share|improve this question
    
Related: (55659) –  Mr.Wizard Aug 2 at 14:12

8 Answers 8

For the filling pattern you showed:

x = {a1, a2, a3, a4, a5, a6};

n = 3;

x ~Internal`PartitionRagged~ Range[n, 1, -1] ~Flatten~ {2} // PadLeft
{{a1, a4, a6}, {0, a2, a5}, {0, 0, a3}}

To find n given a complete input list x you can use:

n = Sqrt[1 + 8 Length@x]/2 - 1/2
share|improve this answer
    
I get the same result without the Flatten which would make your +1 answer even shorter. –  eldo Aug 2 at 15:00
    
@eldo Thanks for vote. However Flatten is needed for the filling order shown in the question. I'll leave the "any order" filling to others, unless I think of something particularly clean. –  Mr.Wizard Aug 2 at 15:05
    
@Mr.Wizard you many need to generalize n. +1 for the Partition trick. –  Algohi Aug 2 at 15:09
    
@Algohi Updated. –  Mr.Wizard Aug 3 at 0:02

Since "It is not important where each element is placed":

a = {a1, a2, a3, a4, a5, a6}
mat = SparseArray[
        Rule[#, #2] & @@@ Thread@{Flatten[Table[{i, j}, {i, 3}, {j, i, 3}], 1], a}];
mat // MatrixForm

$\left( \begin{array}{ccc} \text{a1} & \text{a2} & \text{a3} \\ 0 & \text{a4} & \text{a5} \\ 0 & 0 & \text{a6} \\ \end{array} \right)$

If you have a list of 36 elements that you want to turn into a 8x8 upper triangle matrix:

l = Range@36;
mat = SparseArray[
   Rule[#, #2] & @@@ Thread@{Flatten[Table[{i, j}, {i, 8}, {j, i, 8}], 1], l}];
mat // MatrixForm

$\left( \begin{array}{cccccccc} 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 \\ 0 & 9 & 10 & 11 & 12 & 13 & 14 & 15 \\ 0 & 0 & 16 & 17 & 18 & 19 & 20 & 21 \\ 0 & 0 & 0 & 22 & 23 & 24 & 25 & 26 \\ 0 & 0 & 0 & 0 & 27 & 28 & 29 & 30 \\ 0 & 0 & 0 & 0 & 0 & 31 & 32 & 33 \\ 0 & 0 & 0 & 0 & 0 & 0 & 34 & 35 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 36 \\ \end{array} \right)$


Here is an attempt to make it more robust:

mat[l_] := Module[{n = Abs[1/2 (1 - Sqrt[1 + 8*Length@l])]},
   If[IntegerQ@n, 
     SparseArray[Rule[#, #2] & @@@ Thread@{Flatten[Table[{i, j}, {i, n}, {j, i, n}], 1], l}], 
     "Wrong length. The length should be " <>
      ToString[Or @@ ((#[n]*(#[n] + 1)/2) & /@ {Ceiling, Floor})] <> "."]]

Usage:

l = Range@11;
mat@l

Wrong length. The length should be 15 || 10.

l = Range@10;
mat@l

$\left( \begin{array}{cccc} 1 & 2 & 3 & 4 \\ 0 & 5 & 6 & 7 \\ 0 & 0 & 8 & 9 \\ 0 & 0 & 0 & 10 \\ \end{array} \right)$

share|improve this answer
    
Your answer only functions when there are exactly 6 elements. But the OP wants a more general solution: "... so for example a list with 36 elements shall form a 8x8 upper triangle matrix." –  eldo Aug 2 at 13:39
    
@eldo I assumed that you were capable of replacing 3 by 8 ;o) But there you go. –  Öskå Aug 2 at 13:46
    
Now I can see +1 –  eldo Aug 2 at 13:56

You should try to avoid procedural language in mathematica. I think this should work, but maybe it is not the most efficient:

Code edited for clarity

utMatrix[list_List] := With[{matrixsize = -1/2 + 1/2 Sqrt[1 + 8*Length@list]}, 
PadLeft[Take[list, #], matrixsize, 0] & /@ (Transpose@{Most@#, Rest@# - 1} &
[Accumulate@Join[{1}, Range[matrixsize, 1, -1]]]) 
/;IntegerQ[matrixsize]]

Basically this function partitions the list in sublists of appropriate lengths and then pads them with 0s on the left. The condition at the end checks for lists of wrong lengths.

share|improve this answer

This is if you car about order.

list = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};

s = 1/2 (1 + Sqrt[1 + 8 Length@list]);
l = list[[1 + # s - (# (1 + #))/2 ;; (1 + #) s - ((# + 1) (2 + #))/
         2]] & /@ Range[0, s - 2];
SparseArray[Band[{1, #}] -> l[[#]] & /@ Range[Length@l]] // 
  Normal


(* {{a1, a5, a8, a10}, {0, a2, a6, a9}, {0, 0, a3, a7}, {0, 0, 0, a4}}*)
share|improve this answer

Inspired by Mr. Wizard's solution this is a certain generalization:

rag[v_, w_] := 
 MapThread[v[[#1 ;; #2]] &, With[{a = Accumulate[w]}, {a - w + 1, a}]]

tri[n_Integer /; n > 0, order_: True, s_Symbol: a] :=
 Module[{x, y},
  x = Range[n, 1, -1];
  y = rag[ToExpression[ToString@s <> # & /@ ToString /@ Range@Total@x], x];
  PadLeft@If[order, Flatten[y, {2}], y]
  ]

tri[3] // MatrixForm

enter image description here

tri[8, False] // MatrixForm

enter image description here

share|improve this answer
    
Nice extension. –  Mr.Wizard Aug 2 at 18:35
toUpperMatrix[l_List] := Module[{i, n, m, k, t},
    n = Length[l];
    m = {};
    k = 1/2 (-1 + Sqrt[1 + 8 n]);
    t = {};
    For[i = 1, i <= n, i++,
        AppendTo[t, l[[i]]];
        If[Length[t] == k,
            AppendTo[m, Join[Table[0, {i, 1, 1/2 (-1 + Sqrt[1 + 8 n]) - k}], t]];
            t = {};
            k--;
        ];
    ];
    Return[m];
];

This is the only method I can figure out. Looking forward to better solutions.

share|improve this answer

If you don't care the order you can use the following function:

tpart[list_ /; VectorQ[list] && OddQ[Sqrt[1 + 8 Length[list]]]] := 
 Module[{m = (-1 + Sqrt[1 + 8 Length[list]])/2},
  SparseArray[
   Thread[Flatten[Table[{i, j}, {i, 1, m}, {j, i, m}], 1] -> 
     list], {m, m}]
  ]

For example

tpart[{a1, a2, a3, a4, a5, a6}] // MatrixForm
tpart[Array[a, 36]] // MatrixForm

gives:

Mathematica graphics

If you do care about your order this one (this function is not robust: be sure to pass an appropriately sized list or add a condition):

tpart2[list_] := Module[{m = (-1 + Sqrt[1 + 8 Length[list]])/2, s},
  s = Range[m, 1, -1] //Prepend[1 + Accumulate[#], 1] & //Partition[#, 2, 1] &;
  SparseArray[
   Thread[Array[Band[{1, #}] &, m] -> (Take[list, # - {0, 1}] & /@ s)]
   , {m, m}]
  ]

tpart2[list]
tpart2[list] // MatrixForm
tpart2[list] // Normal

The result is:

share|improve this answer
  n = 6
  vals = Array[a, {n (n + 1)/2}]
  SparseArray[
       SortBy[Tuples[Range[n], {2}] ,
         #[[2]] - #[[1]] &][[-n (n + 1)/2 ;;]] -> vals ] // MatrixForm

enter image description here

without using SparseArray:

 ReplacePart[ConstantArray[0, {n, n}],
      MapThread[#1 -> #2 &, {
         SortBy[Tuples[Range[n], {2}] ,
         #[[2]] - #[[1]] &][[-n (n + 1)/2 ;;]], vals}]] // MatrixForm
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.