I have 3 lists:

numbers = {{1, 2}, {3, 4}, {5, 6}};
toUpdate = {{1, 0}, {0, 0}, {1, 1}};
newValues = {{10, 20}, {30, 40}, {50,60}};

I have to update the list numbers such that, if the value in an a particular index {i,j} in toUpdate is 1, then the value in newValues is copied to numbers.

i.e. for the above example the final result should be,

number = {{10, 2}, {3, 4}, {50, 60}};

In the toUpdate list there will be 50% of 0s and 50% of 1s.

So far the best way I know is to use Rule or to use Do[]. I am skeptical of using both of these methods because,

  • Rule creates a new list and has to copy all the numbers.
  • With Do[] I can update in place, but results in a larger piece of code and I want to eliminate it.

PS: Is there a way to update in place if there is a function instead of toUpdate list?

  • $\begingroup$ All Answers are better, but I am going to accept that of @kguler, because it modifies the original list itself, the way I want. $\endgroup$ – ManojRK Dec 29 '14 at 7:59
  • $\begingroup$ It seems your view how Mathematica works is wrong. You can check what names are created with e.g. Names["Global'*"] (apostrophe after Global). If you are to modify the original list you can do: numbers = numbers Abs[toUpdate - 1] + toUpdate newValues;. Of course my solution is simply the best but I wouldn't like to change your choice. $\endgroup$ – Artes Dec 29 '14 at 15:10
  • $\begingroup$ @Artes, Sorry I am new to Mathematica, I am a .Net developer by profession. To my knowledge, creating a completely new list and to fill it, instead of changing a few values is not optimal. I have worked with Matlab before, and there is a way to update specific elements in a list based on a matrix or a function. I want a similar optimal solution, because I will be doing this operation around a million times in one go and it takes more than a minute for the complete execution. $\endgroup$ – ManojRK Dec 29 '14 at 20:57
  • $\begingroup$ As you said there are 50% 0's and 1's so if you work with sufficiently long lists there is no way to outperform basic Plus and Times operations, therefore I have said it is the best way. And of course when you gain some experience with Mathematica you'll see how it is different than standard compilable programming languages. $\endgroup$ – Artes Dec 29 '14 at 21:07
(numbers[[##]]=newValues[[##]])&@@@Position[toUpdate,1]; (* thanks: Karsten7 *)
(*  {{10,2},{3,4},{50,60}}  *)
  • $\begingroup$ Or (numbers[[##]] = newValues[[##]]) & @@@ Position[toUpdate, 1]; $\endgroup$ – Karsten 7. Dec 28 '14 at 18:20

You might use Position

pos = Position[toUpdate, 1] obtains, from toUpdate, the positions that you need to update and stores them in pos.

Extract[newValues, pos] finds the values to be inserted. They are at the same positions in the list, newValues.

ReplacePart inserts those values in the proper places--same positions, once again--in numbers.

pos = Position[toUpdate, 1]
ReplacePart[numbers, Thread[pos -> Extract[newValues, pos]]]

{{10, 2}, {3, 4}, {50, 60}}


Because of lisatability of Iimes, Plus and Abs (see the Listable attribute and examine the full form of the underlying expression, moreover take a look at a fine structure of list addition in Mathematica e.g. Adding Lists Together) one can do simply this:

numbers Abs[toUpdate - 1] + toUpdate newValues
{{10, 2}, {3, 4}, {50, 60}}

This solution exploits a specific form of toUpdate list and most likely it should be the fastest one however in more general cases there is a vast space of possible operations on lists. See also the structure of the above operation using Inactive (new in Mathematica 10):

FullForm[ Inactive[ numbers Abs[toUpdate - 1] + toUpdate newValues]]
  • $\begingroup$ @DavidCarraher Thanks, I like your approach as well (+1) since it can be easily generalized. $\endgroup$ – Artes Dec 28 '14 at 16:26

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.