2
$\begingroup$

I am trying to use If function over a nested list below, to generate a new list that any element greater than 1 will be set to 0. Example list:

{{1, 2, 3}, {-0.1, 0.5, 0.9, 1.1, 2}, {2, 3, 0.3}}

Result:

{{0, 0, 0}, {-0.1, 0.5, 0.9, 0, 0}, {0, 0, 0.3}}    

I thought this was simple, but I tried sth like fun[x_]:= If[x<1,x,0] and mapping it to the list, it turns out it cannot work on a nested list. Sorry if the question was asked, try to find a solution but failed!

$\endgroup$
6
$\begingroup$
lstlst = {{1, 2, 3}, {-0.1, 0.5, 0.9, 1.1, 2}, {2, 3, 0.3}}
lstlst /. {x_ /; x >= 1 -> 0}

or, if you really prefer to use Map with If, set the levelspec:

Map[If[# >= 1, 0, #] &, lstlst, {2}]
$\endgroup$
  • $\begingroup$ Thank u very much! $\endgroup$ – cj9435042 Dec 28 '17 at 17:04
5
$\begingroup$
lst = {{1, 2, 3}, {-0.1, 0.5, 0.9, 1.1, 2}, {2, 3, 0.3}}; 

lst (1 - UnitStep[lst - 1])

{{0, 0, 0}, {-0.1, 0.5, 0.9, 0, 0}, {0, 0, 0.3}}

Alternatively, you can also Map your fun at Level {-1}:

fun[x_] := If[x < 1, x, 0]

Map[fun, lst, {-1}]

{{0, 0, 0}, {-0.1, 0.5, 0.9, 0, 0}, {0, 0, 0.3}}

$\endgroup$
2
$\begingroup$

One other solution to the problem is to use

sel = Function[x, If[x < 1, x, 0], Listable]

The function sel performs the comparison that is discussed in the body of the question (see Question) and returns the argument it is passed (ie x) when that is less than unity (and zero otherwise).

It also carries the Listable attribute ie it is automatically threaded over lists eg sel[{1,2,3}] returns {0,0,0} as expected. This behavior would not have been possible without Listable.

Now, applying the sel function on the input (ragged) list will produce the requested result. Please verify that evaluating

Apply[sel[{##}] &, lst, -1] == res

returns True, where lst={{1, 2, 3}, {-0.1, 0.5, 0.9, 1.1, 2}, {2, 3, 0.3}} is the input list and res={{0, 0, 0}, {-0.1, 0.5, 0.9, 0, 0}, {0, 0, 0.3}} is the desired output.

$\endgroup$
2
$\begingroup$

You could use Clip:

list = {{1,2,3}, {-0.1,0.5,0.9,1.1,2}, {2,3,0.3}};
Clip[
    list,
    {Min[list], 1-$MachineEpsilon},
    {0,0}
]

{{0, 0, 0}, {-0.1, 0.5, 0.9, 0, 0}, {0, 0, 0.3}}

Update

Since there is a fair number of answers now, we can compare. Here is a dataset:

data = RandomReal[2, {10^5,10}];

Here are the various answers:

f1[data_] := data /. x_ /; x>=1 -> 0 (* Alan *)
f2[data_] := Map[If[# >= 1, 0, #]&, data, {2}] (* Alan *)
f3[data_] := Apply[Function[x, If[x<1, x, 0], Listable][{##}]&, data, -1] (* user42582 *)
f4[data_] := data (1 - UnitStep[data - 1]) (* kglr *)
f5[data_] := Map[If[# < 1, #, 0]&, data, {-1}] (* kglr *)
f6[data_] := Clip[data, {Min[data], 1-$MachineEpsilon}, {0, 0}] (* Carl *)

Here is the comparison:

r1 = f1[data]; //RepeatedTiming
r2 = f2[data]; //RepeatedTiming
r3 = f3[data]; //RepeatedTiming
r4 = f4[data]; //RepeatedTiming
r5 = f5[data]; //RepeatedTiming
r6 = f6[data]; //RepeatedTiming

N @ r1 === N @ r2 === N @ r3 === N @ r4 === N @ r5 === N @ r6

{0.84, Null}

{0.9662, Null}

{1.42, Null}

{0.00706, Null}

{0.96, Null}

{0.0037, Null}

True

Summarizing, my answer is the fastest with @kglr's a close second. The others are about the same.

$\endgroup$
  • $\begingroup$ Another variation using Clip: Clip[list, {-Infinity, 1}] //. {1 -> 0} $\endgroup$ – bill s Dec 28 '17 at 20:37

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.