2

I want to know the simplest way to write this conditional copy function.

I have 2 arrays of the same size:

 a={0,1,2,3,4}
 b={0,0,0,0,0}

I want b to copy a's element, if that element is bigger than 2.

expected result is :

 b={0,0,0,3,4}

Appreciate anyone gives a hint. Thanks.

David G. Stork
  • 41,180
  • 3
  • 34
  • 96
user1470393
  • 279
  • 1
  • 8

3 Answers3

3

While there are plenty of decent answers in the comments, I wanted to provide a couple pieces of information about why the solutions are generally complicated and why this question is odd for Mathematica.

Primarily, something that is true for Mathematica but that is generally hidden from you as a user is that the lists and data in Mathematica are usually immutable, meaning that you do not really 'copy' items from a to b; instead, you create a new list that has some elements of a and some elements of b. In languages like Matlab, you can do something along the lines of b[a>2] = a[a>2], in which the elements of b get overwritten in place. This is not possible in Mathematica because the underlying list is immutable. If you are used to a language like Matlab, this may seem unintuitive, but it allows for several kinds of optimization (data never needs to be copied, multiple threads can be employed without worries about race conditions, etc.).

Instead of copying elements around, the usual way to approach this problem is to operate over the data simultaneously, building up a new representation; here are a few examples:

b = If[#1 > 2, #1, #2] & @@@ Transpose[{a, b}]

{0,0,0,3,4}

b = Function[{aa, bb}, If[aa > 2, aa, bb], {Listable}][a, b]

{0,0,0,3,4}

Note that the statement b = ... looks like mutability (and in a sense, it is); symbol bindings are mutable, as is basically everything in Mathematica's underlying pattern matching machinery. In other words, you can rebind b to a new data value, but you cannot change the data that b points to.

nben
  • 2,148
  • 9
  • 20
  • 1
    (Note that I didn't add J. M.'s solution here because while it's short and elegant, my reading of the question is that the OP is asking about the equivalent of Matlab's b[a > 2] = a[a > 2] syntax and not about the specific case in which a UnitStep is appropriate.) – nben May 11 '17 at 19:07
  • What about a[[5]] = 6? – Kuba May 11 '17 at 19:26
  • I'm not a Wolfram dev so I don't know how that is implemented internally, but a simple way that it could be is like this: Set[Part[x_, i_], val_] := Set[x, ReplacePart[x, i -> val]]. Such changes can be made nearly O(1) with the right data structures (e.g., clojure's immutable vectors). They may alternately do some internal reference counting even if the representation is considered immutable and allow changes when it is not shared. Hard to say, but I don't think that its presence in the language requires mutability, and most of the Mathematica toolkit treats data as persistent regardless. – nben May 12 '17 at 00:54
1

It is unclear why the poser defined b in the problem. If the values of b are irrelevant, then the elegant solution from J. M. is perfect:

b = a UnitStep[a - 3]

If however (and as I suspect) an entry of b is to remain if the corresponding value of a is less than 3, then this solution works:

b = MapThread[If[#1 > 2, #1, #2] &, {a, b}]
David G. Stork
  • 41,180
  • 3
  • 34
  • 96
1
b = Clip[a, {3, ∞}, {0, ∞}]

{0, 0, 0, 3, 4}

kglr
  • 394,356
  • 18
  • 477
  • 896