4
$\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$
6
  • $\begingroup$ You can directly do {M[[1, 1]], M[[1, 3]], M[[2, 3]]} = values? Or do you want it automated? $\endgroup$
    – march
    Commented Sep 29, 2016 at 16:54
  • $\begingroup$ Yes, I want to have it automated because I want to work with much larger lists of matrix elements. $\endgroup$ Commented Sep 29, 2016 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$ Commented Sep 29, 2016 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
    Commented Sep 29, 2016 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
    Commented Sep 29, 2016 at 17:19

5 Answers 5

6
$\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$
4
  • $\begingroup$ Thanks, this works perfectly also with a small caveat I forgot to add to the question. $\endgroup$ Commented Sep 29, 2016 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$ Commented Sep 29, 2016 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
    Commented Sep 29, 2016 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$ Commented Sep 30, 2016 at 10:59
9
$\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$
3
$\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$
3
$\begingroup$
list = {{1, 1}, {1, 3}, {2, 3}};
values = {a, b, c};
m = Array[1 &, {3, 3}];

Combining ApplyTo (new in 12.2) and ReplaceAt (new in 13.1)

m //= ReplaceAt[Thread[list -> values], All];

m

{{a, 1, b}, {1, 1, c}, {1, 1, 1}

$\endgroup$
2
$\begingroup$

Using SubsetMap:

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

SubsetMap[values &, m, list]

(*{{a, 1, b}, {1, 1, c}, {1, 1, 1}}*)
$\endgroup$
2
  • 1
    $\begingroup$ +1 - This is the way to go! $\endgroup$
    – eldo
    Commented Jan 7 at 0:13
  • $\begingroup$ Thanks, @eldo! :-) $\endgroup$ Commented Jan 7 at 0:38

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.