2
$\begingroup$

Suppose I have a matrix M, a list

list= {{1,1}, {1,3}, {2,3}};

and a list of

values = {a,b,c}

How do I set the matrix elements {M[[1,1]], M[[1,3]], M[[2,3]]} = values?

This will produce the list elements I want:

Map[P[[Apply[Sequence, #]]] &, list] = {M[[1,1]], M[[1,3]], M[[2,3]]}

but the final command is Map, which is protected, and hence I cannot use it to set the list elements to the elements of values.

Of course one way of doing this is by looping,

For[i=1, i<=Length[list], i++, M[[Sequence @@ list[[i]] = values[[i]]]

However, since I would like to work with very large lists of indices I want to avoid loops as much as possible.

$\endgroup$
  • $\begingroup$ You can directly do {M[[1, 1]], M[[1, 3]], M[[2, 3]]} = values? Or do you want it automated? $\endgroup$ – march Sep 29 '16 at 16:54
  • $\begingroup$ Yes, I want to have it automated because I want to work with much larger lists of matrix elements. $\endgroup$ – Yiteng Sep 29 '16 at 16:57
  • $\begingroup$ I also want to avoid loops, otherwise For[i=1, i<=Length[list], i++, M[[Sequence @@ list[[i]] = values[[i]]] would be an easy solution. $\endgroup$ – Yiteng Sep 29 '16 at 16:59
  • 1
    $\begingroup$ Are you modifying an existing matrix? Or are you declaring the matrix first and then putting in entries? Because if you are just making the matrix to begin with, you can do M = Normal@SparseArray[Thread[list -> values], {3, 3}]. $\endgroup$ – march Sep 29 '16 at 17:06
  • $\begingroup$ @march Can it be done with ##? To pass list and values like in M[[1, 1]] = a. I attempted M[[##]] & /@ list = values but failed. $\endgroup$ – corey979 Sep 29 '16 at 17:19
4
$\begingroup$

Given the structure that you've set up, I would probably accomplish this using MapThread. Taking

list = {{1, 1}, {1, 3}, {2, 3}};
values = {a, b, c};
m = ConstantArray[1, {3, 3}]
(* {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} *)

do:

MapThread[(m[[Sequence @@ #1]] = #2) &, {list, values}];
m
(* {{a, 1, b}, {1, 1, c}, {1, 1, 1}} *)

Alternatively,

Scan[(m[[Sequence @@ list[[#]]]] = values[[#]]) &, Range@Length@list];

But if you are actually just creating the matrix to begin with, I would use SparseArray to construct the matrix from scratch, i.e.

Normal@SparseArray[Thread[list -> values], {3, 3}]
(* {{a, 0, b}, {0, 0, c}, {0, 0, 0}} *)
$\endgroup$
  • $\begingroup$ Thanks, this works perfectly also with a small caveat I forgot to add to the question. $\endgroup$ – Yiteng Sep 29 '16 at 17:21
  • $\begingroup$ If I would like to keep the old values and add up the values at these indices, then MapThread[(m[[Sequence @@ #1]] += #2) &, {list, values}]; does the job, but SparseArray and ReplacePart would erase the old values. $\endgroup$ – Yiteng Sep 29 '16 at 17:23
  • $\begingroup$ But if that was the case, then I would do something like m = m + SparseArray[Thread[list -> values], {3, 3}]. $\endgroup$ – march Sep 29 '16 at 17:25
  • $\begingroup$ What if the first list you feed already has duplicates which need to be added up? Then seems not easy to do this without introducing some iterative process or loop. $\endgroup$ – Yiteng Sep 30 '16 at 10:59
7
$\begingroup$

You can use ReplacePart and get around the difficulties with Set

m = ConstantArray[1, {3, 3}]
m = ReplacePart[m, Thread[list -> values]]
(* {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} *)
(* {{a, 1, b}, {1, 1, c}, {1, 1, 1}} *)
$\endgroup$
2
$\begingroup$

for fun we can do this all with SparseArray..

m = Partition[Range[12], 3];
list = {{1, 1}, {1, 2}, {4, 3}};
values = {a, b, c};
m = SparseArray[list -> 0, Dimensions@m, 1] m + 
          SparseArray[list -> values, Dimensions@m] 

{{a, b, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, c}}

or even

m + SparseArray[list -> values - Extract[m, list], Dimensions@m]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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