2
$\begingroup$

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.

$\endgroup$
8
  • 5
    $\begingroup$ b = a UnitStep[a - 3]? $\endgroup$ Commented May 11, 2017 at 16:10
  • 2
    $\begingroup$ Yeap, or alternative MapThread[If[#1 > 2, #1, #2] &, {a, b}] $\endgroup$ Commented May 11, 2017 at 16:11
  • 1
    $\begingroup$ My solution is more complex. Thread[Complex[b, a]] /. Complex[x_, y_] /; y > 2 -> Complex[y, x] //Re $\endgroup$
    – webcpu
    Commented May 11, 2017 at 17:16
  • 2
    $\begingroup$ We need an "inverse golf" or "Rube Goldberg" contest for the most complex or inefficient code to solve a simple problem! Creativity gets points! $\endgroup$ Commented May 11, 2017 at 18:18
  • 1
    $\begingroup$ Do we know b is all zero to begin with and what if it is not? $\endgroup$
    – george2079
    Commented May 11, 2017 at 19:52

3 Answers 3

3
$\begingroup$

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.

$\endgroup$
3
  • 1
    $\begingroup$ (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.) $\endgroup$
    – nben
    Commented May 11, 2017 at 19:07
  • $\begingroup$ What about a[[5]] = 6? $\endgroup$
    – Kuba
    Commented May 11, 2017 at 19:26
  • $\begingroup$ 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. $\endgroup$
    – nben
    Commented May 12, 2017 at 0:54
1
$\begingroup$

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}]
$\endgroup$
1
$\begingroup$
b = Clip[a, {3, ∞}, {0, ∞}]

{0, 0, 0, 3, 4}

$\endgroup$
1
  • 2
    $\begingroup$ This is the canonical way. +1 $\endgroup$
    – ciao
    Commented May 20, 2017 at 22:52

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.