9
$\begingroup$
A[[{2, 3, 5}]] = {97,98,99}

changes 2,3,5-th elements of A to 97,98,99 respectively.

Similary

A[[{2, 3, 5}]] = 100

changes 2,3,5-th elements of A to 100.

Above technique is simple, fast. It clearly works for 1D-list.

I want to know if there is a method for 2D-list, that slightly modified the above example for 1D.

Here is my trial :

A = {{91, 34, 82, 61, 6}, {34, 1400, 48, 60, 56}, {99, 72, 7500, 43, 73}, {44, 47, 4, 68, 94}, {2, 72, 61, 35, 5000}};

Position[A, _?(Mod[#, 100] == 0 &), {2}]
{{2, 2}, {3, 3}, {5, 5}}

A[[Delete[#, 0]]] & /@ {{2, 2}, {3, 3}, {5, 5}}
{1400, 7500, 5000}

A[[Delete[#, 0]]] & /@ {{2, 2}, {3, 3}, {5, 5}} = {9999, 9999, 9999};
(*My trial has failed. No output with an error message*)

If there is no 1D-analogue of 2D, what would be simple, fast method for 2D ?

A related post (about the performance of 1D case) :

Applying f for a part of list (MapAt is slow)

+-+-+-+-+-+- After Nasser's and Michael E2's answer +-+-+-+-+-+-+-

Thank you, answerers. Nasser's method is standard method and Micahel E2's method is another method, also I found yet another method. I tested it for large case :

kamo = 10000 rows/10000 columns of integers below 10000
ramo = list of positions of kamo that we want to replace (50% of kamo, namely 50000000 numbers will be replaced)
pamo = we will replace 50% of kamo with pamo.

Rather surprisingly, in my PC (Mathematica V12.2),

Imda K's method : 4.8 seconds
Michael E2's method : 187 seconds
Nasser's standard method : krenel crashes

Screenshot: enter image description here

SeedRandom[1234]; kamo = RandomInteger[10000, {10000, 10000}];
ramo = RandomSample[Tuples[Range[10000], 2], 10000^2/2];
pamo = RandomInteger[10000, 10000^2/2];

(kamo2 = Join @@ kamo;
  ramo2 = 10000 (#[[1]] - 1) + #[[2]] & /@ ramo;
  kamo2[[ramo2]] = pamo;
  kamo3 = Partition[kamo2, 10000];) // Timing


MapThread[
  Function[{pos, val}, 
   With[{part = Sequence @@ pos}, kamo[[part]] = val]], {ramo, pamo}]; //Timing

ReplacePart[kamo, AssociationThread[ramo, pamo]]; // Timing (*This may crash kernel *)

In the above case, each element of kamo had the same length, 10000. But what if they had different lengths ? Well, I am sure it doesn't get in the way to use my method. And I think this method can be generalized to list of complicated structure. But the thing that makes me crave the most is.. Wolfram company can do something about this? (Upgrade the performance of ReplacePart)

$\endgroup$
4
  • 1
    $\begingroup$ As Leonid Shifrin has commented here "The big problem with ReplacePart is that it copies entire list rather than modify a part in-place". Your 1D methods modifiy in place. Are you specifically looks for an equivalent method for 2D list that modifies the original list (as does the Michael E2 method), or do you want a copy where the original list is unaltered? $\endgroup$
    – user1066
    Commented Jun 12, 2022 at 23:08
  • $\begingroup$ Your method is very nice, and certainly very fast, and cleverly uses modification-in-place to make the changes to a flattened copy. It does not modify the original list, but returns a new list (both Join and Partition will produce new lists?) but it is much faster (as you have shown) than both ReplacePart and the modification-in-place methods, and IMO you should write it up as a separate answer. $\endgroup$
    – user1066
    Commented Jun 13, 2022 at 20:55
  • 1
    $\begingroup$ I (naively?) implemented your method as follows: g[list2D_,positions_,newvals_]:=Module[{ len=Dimensions[list2D][[2]], listFlat=Flatten@list2D},positionsFlat = len (#[[1]] - 1) + #[[2]] & /@ positions; listFlat[[positionsFlat]] = newvals; Partition[listFlat, len] ] $\endgroup$
    – user1066
    Commented Jun 13, 2022 at 20:56
  • 1
    $\begingroup$ On my system the above is about 25X faster than Scan[(kamo[[Sequence@@#[[1]]]]=#[[2]])&,Transpose[{ramo,pamo}]]; (which modifies in place) using the example you provide $\endgroup$
    – user1066
    Commented Jun 13, 2022 at 21:00

4 Answers 4

14
$\begingroup$

Another option is to use ReplacePart

(A = {{91, 34, 82, 61, 6}, {34, 1400, 48, 60, 56}, {99, 72, 7500, 43, 
     73}, {44, 47, 4, 68, 94}, {2, 72, 61, 35, 5000}}) // MatrixForm
idx = {{2, 2}, {3, 3}, {5, 5}};
ReplacePart[A, idx -> 9999] // MatrixForm

Mathematica graphics

ReplacePart Takes as second argument the positions to change and the value to change these to.

If you want different value for each position instead of the same value like the above, you can use the syntax

ReplacePart[A, {{2, 2} -> 1, {3, 3} -> 2, {5, 5} -> 33}]

Mathematica graphics

$\endgroup$
12
$\begingroup$
aa = {
 {91,   34,   82, 61,    6},
 {34, 1400,   48, 60,   56},
 {99,   72, 7500, 43,   73},
 {44,   47,    4, 68,   94},
 {2,    72,   61, 35, 5000}};

MapThread[Function[{pos, val},
   With[{part = Sequence @@ pos}, aa[[part]] = val]
   ],
  {{{2, 2}, {3, 3}, {5, 5}},
   {9999, 9999, 9999}}];

aa
$\endgroup$
2
$\begingroup$
m =
  {{91, 34, 82, 61, 6},
   {34, 1400, 48, 60, 56},
   {99, 72, 7500, 43, 73},
   {44, 47, 4, 68, 94},
   {2, 72, 61, 35, 5000}};

idx = {{2, 2}, {3, 3}, {5, 5}};

Using ReplaceAt (new in 13.1)

ReplaceAt[_ :> 100, idx] @ m

returns

{{91, 34, 82, 61, 6}, 
{34, 100, 48, 60, 56}, 
{99, 72, 100, 43, 73}, 
{44, 47, 4, 68, 94}, 
{2, 72, 61, 35, 100}}

Using MapAt

MapAt[100 &, idx] @ m

(* same result *)

$\endgroup$
2
$\begingroup$
m =
  {{91, 34, 82, 61, 6},
   {34, 1400, 48, 60, 56},
   {99, 72, 7500, 43, 73},
   {44, 47, 4, 68, 94},
   {2, 72, 61, 35, 5000}};

idx = {{2, 2}, {3, 3}, {5, 5}};

Using SubsetMap:

SubsetMap[100 + Subtract[#, #] &, m, idx] // TeXForm

$\left( \begin{array}{ccccc} 91 & 34 & 82 & 61 & 6 \\ 34 & 100 & 48 & 60 & 56 \\ 99 & 72 & 100 & 43 & 73 \\ 44 & 47 & 4 & 68 & 94 \\ 2 & 72 & 61 & 35 & 100 \\ \end{array} \right)$

$\endgroup$

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.