11
$\begingroup$

I'm trying to find a generic way (for arbitrary dimensions) to create a matrix like so

a[1] a[2]

a[3] a[4]

i.e where it is indexed by one number, instead of say Array[a, {2, 2}] which gives

a[1,1] a[2,1]

a[2,1] a[2,2]

I hope you can help!

$\endgroup$
0

9 Answers 9

17
$\begingroup$

Partition[ Array[a, 4], 2] will do it.

In general,

makeMat[n_, m_] := Partition[ Array[a, n*m], m]
$\endgroup$
1
  • $\begingroup$ Perfect! Exactly what I sought for. Thanks a bunch. $\endgroup$
    – Henrik
    Apr 1, 2016 at 12:01
6
$\begingroup$

With a little indexing arithmetic, one can use only Array[] to generate the required matrix:

With[{m = 4, n = 4},
     Array[C[n (#1 - 1) + #2] &, {m, n}]]
   {{C[1], C[2], C[3], C[4]}, {C[5], C[6], C[7], C[8]},
    {C[9], C[10], C[11], C[12]}, {C[13], C[14], C[15], C[16]}}
$\endgroup$
6
$\begingroup$
matF1 = Partition[# /@ Range[#2 #3], #3] &
matF2 = ArrayReshape[Array[#, Times[##2]], {##2}] & (* thanks: J.M. *)

{matF1[a, 2, 3], matF2[a, 2, 3]}

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

matF2[a, 2, 3, 2]

{{{a[1], a[2]}, {a[3], a[4]}, {a[5], a[6]}},
{{a[7], a[8]}, {a[9], a[10]}, {a[11], a[12]}}}

$\endgroup$
4
  • 1
    $\begingroup$ Hm, is there really a good reason to use Map and Range instead of combining them into a single Array call like Szabolcs did? $\endgroup$ Apr 1, 2016 at 12:52
  • $\begingroup$ @MartinBüttner, not really:) - just another way. $\endgroup$
    – kglr
    Apr 1, 2016 at 12:55
  • 2
    $\begingroup$ Alternatively: matF2 = ArrayReshape[Array[#, Times[##2]], {##2}] & This more general form can now yield tensors instead of just matrices: matF2[a, 2, 3, 4] $\endgroup$ Apr 1, 2016 at 14:53
  • $\begingroup$ @J.M. great point, thank you. $\endgroup$
    – kglr
    Apr 1, 2016 at 15:12
4
$\begingroup$

Another method,

makeMat[n_, m_] := 
 Map[a, Array[#2 &, {n, m}] + m Range[0, n - 1], {2}]

makeMat[4, 5] // MatrixForm

enter image description here

$\endgroup$
2
  • $\begingroup$ As always, I am indebted to you for spotting my mistakes :-) $\endgroup$
    – Jason B.
    Apr 1, 2016 at 12:33
  • $\begingroup$ :) Now I can upvote. Here is a slot-free version: makeMat[n_, m_] := Map[a, ConstantArray[Range[m], n] + m Range[0, n - 1], {2}] $\endgroup$ Apr 1, 2016 at 12:33
3
$\begingroup$

It's like the opposite of code-golf,

With[
 {n = 3, m = 5},
 mat = ConstantArray[1, {n, m}];
 i = 1;
 For[j = 1, j <= n, j++,
  For[k = 1, k <= m, k++,
   mat[[j, k]] = a[i];
   i++;
   ]
  ];
 ]
mat // MatrixForm

enter image description here

$\endgroup$
4
  • $\begingroup$ My word... use Do[], for the love of heaven! :P $\endgroup$ Apr 1, 2016 at 15:11
  • $\begingroup$ Well, this was a tongue-in-cheek post, I could delete it if those aren't really welcome here $\endgroup$
    – Jason B.
    Apr 1, 2016 at 15:12
  • 1
    $\begingroup$ Does the date today have anything to do with why you posted this? ;) $\endgroup$ Apr 1, 2016 at 15:13
  • 2
    $\begingroup$ Oh dear lord, today is the day to look skeptically at the internet isn't it? $\endgroup$
    – Jason B.
    Apr 1, 2016 at 15:14
2
$\begingroup$
    n = 4;
    lst = Table[a[i], {i, 0, n}]
    A = Partition[lst, n/2] // MatrixForm

    a[1]    a[2]
    a[3]    a[4]
$\endgroup$
2
$\begingroup$

Here is a way that works with arbitrary dimension arrays, without using a dummy counter index:

SparseArray[MapIndexed[# -> a[First@#2] &,
     Sort[Flatten[MapIndexed[ #2 & , #, {-1}],
       Depth[#] - 2]]]] &@Array[0&, {2, 4, 2}] 

enter image description here

even play with SortBy to tweak the ordering:

SparseArray[MapIndexed[# -> a[First@#2] &,
     SortBy[Flatten[MapIndexed[ #2 & , #, {-1}],
       Depth[#] - 2], {#[[1]], #[[3]], #[[2]]} &]]] &@
  Array[0&, {2, 4, 2}]

enter image description here

and a variant that works with arbitrary lists:

ReplacePart[#,
   MapIndexed[# -> a[First@#2] &, 
    Sort[Position[#, x_ /; AtomQ[x], Heads -> False]]]] &@
 {{0, {0, 0, 0}}, {0, 0, {0, 0}}}

{{a[1], {a[4], a[5], a[6]}}, {a[2], a[3], {a[7], a[8]}}}

$\endgroup$
1
$\begingroup$

Here's another take (although I would have actually done it Szabolcs's way).

mat = {{f, "x"}, {1, Sin[23]}}
Module[{i = 1}, Replace[mat, _ :> a[i++], {2}]]
(* {{f, "x"}, {1, Sin[23]}} *)
(* {{a[1], a[2]}, {a[3], a[4]}} *)
$\endgroup$
1
$\begingroup$

One more way:

ClearAll@a
Block[{i = 1}, Array[a[i++] &, {3, 4}]] // MatrixForm
$\endgroup$
4
  • $\begingroup$ This is in the same spirit as march's answer. $\endgroup$ Apr 1, 2016 at 15:03
  • $\begingroup$ Is there a reason to use Block instead of Module here? Somewhat related, why doesn't using Module here prevent the introduction of the name i into the global namespace? I would have expected that difference. $\endgroup$
    – Alan
    Apr 1, 2016 at 15:26
  • 1
    $\begingroup$ @Alan. Actually, one shouldn't use Block here. I've been "chastised" about that before.. $\endgroup$
    – march
    Apr 1, 2016 at 16:33
  • $\begingroup$ One other question: this approach depends on the array being filled in row-major order. This is currently true, but is it documented/guaranteed? $\endgroup$
    – Alan
    Apr 3, 2016 at 14:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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