15

This question could sound pretty silly but I can't find a way to apply element -wise tests to a list.

For example if I digit

{0.6, 1.2}>1
{{0.6,1.2},{5,0.1}}>1

I would expect to obtain

{False,True}
{{False,True},{True, False}}

respectively, but it is not the case.

Of course I can define a function or using Map, but I can't believe there is not a core function providing this kind of result. Thank you for any indication

rhermans
  • 36,518
  • 4
  • 57
  • 149
dario
  • 337
  • 3
  • 7

6 Answers6

21

To my knowledge, there aren't built-in versions for comparison operators that would be automatically threaded over lists. One reason for that is that Mathematica is a symbolic system, and every auto-simplification has a cost, because there may be cases when this isn't desirable.

It is relatively easy however to construct the behavior you want:

ClearAll[l];
l[f_] := Function[Null, f[##], Listable]

Now, you can call:

{{0.6, 1.2}, {5, 0.1}} ~ l[Greater] ~ 1

(* {{False, True}, {True, False}} *)

and similarly with other comparison operations.

Note that, since you didn't mention efficiency, I intentionally left this aspect out. If you have large numerical lists, there are vastly more efficient ways to perform the comparisons, making use of vectorization and packed arrays.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • I don't fully get the sintax (I'm just a beginner) but this function does what I was looking for. Thank you – dario Sep 29 '15 at 17:08
  • 2
    @dario [1/2] The syntax a ~ f ~ b is called infix notation, and is equivalent to f[a,b], but sometimes looks more natural. Like in this case, where it allows to somewhat make up for the notational convenience of comparison operator symbols. The expression a > b can be equivalently rewritten as Greater[a,b] in Mathematica, and similarly for other operators. So, we could also write a ~ Greater ~ b, which doesn't look bad. Now, from this form, my suggestion is only one step further. The function l I proposed is similar in spirit to Python decorator. It takes another function and ... – Leonid Shifrin Sep 29 '15 at 17:56
  • @dario [2/2] ... makes it Listable - that is, wraps it in a pure function that has a Listable attribute. Due to the way evaluation sequence works in Mathematica, this leads to threading of the function over lists, before it gets applied to the individual elements. As a result, the construct l[Greater] would automatically work on lists of any dimensionality, compared to a single number - as well as for e.g. comparison of two lists with the same dimensions - like say {1,3,5} ~ l[Greater] ~ {6,4,2}. Thanks for the accept. – Leonid Shifrin Sep 29 '15 at 17:59
  • Is it correct to think of l as a function that defines a pure function? (specifically, it looks likeluses the inputfto define a pure function based onf`?) – user106860 Nov 12 '20 at 19:04
  • @user106860 I think, the simplest way to think of l is that it is similar to a decorator in python. It takes a function and returns a modified function which adds listability (which happens to be implemented using Function, but that's an implementation detail). – Leonid Shifrin Nov 12 '20 at 19:55
18

The BoolEval` package does exactly this. For example:

BoolEval[{0.6, 1.2} > 1]
(* Out: {0, 1} *)

and

BoolEval[{{0.6, 1.2}, {5, 0.1}} > 1]
(* Out: {{0, 1}, {1, 0}} *)

In order to return True and False instead of 0 and 1, you can append /. {0 -> False, 1 -> True}.

C. E.
  • 70,533
  • 6
  • 140
  • 264
  • This solution work as well as the one I've chosen as "best answer", and is probably more elegant. I haven't chosen this, though, because it requires additional packages. Thank you anyway. – dario Sep 29 '15 at 17:12
9

Depth 1

MapAt[Greater[#, 1] &, {0.6, 1.2}, {All}]
{False, True}

OR

Thread[Greater[#, 1]] & @ RandomReal[2, 10]
{True, False, False, True, True, True, False, False, False, True}

Depth 2

MapAt[Greater[#, 1] &, {{0.6, 1.2}, {5, 0.1}}, {All, All}]
{{False, True}, {True, False}}

OR

Thread[Greater[#, 1]] & /@ RandomReal[2, {3, 5}]
{{True, True, False, True, True}, 
 {True, False, False, False, False},
 {False, False, False, False, True}}

Depth n

f=MapAt[Greater[#, 1] &, #, Table[All, (Depth[#] - 1)]] &

f[{{{1.6, 0.2}, {3, 0.1}}, {{0.6, 1.2}, {5, 0.1}}}]
{{{True, False}, {True, False}}, {{False, True}, {True, False}}}
f@RandomReal[2, Range[6]]

Mathematica graphics

OR

RandomReal[2, Range[4]] /. (w_Real -> w > 1)
rhermans
  • 36,518
  • 4
  • 57
  • 149
8

The first example can be done with

Thread[{0.6, 1.2} > 1]

$\ ${False, True}

For the second example Map has to be used for this approach, but maybe in a different way than you excluded in you question:

Thread /@ Thread[{{0.6, 1.2}, {5, 0.1}} > 1]

$\ ${{False, True}, {True, False}}

Karsten7
  • 27,448
  • 5
  • 73
  • 134
7

Check Positive.

For {0.6, 1.2}>1, you may write:

Positive[{0.6, 1.2}-1]
Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
Jake Pan
  • 526
  • 3
  • 10
2

For the better read,I post this solution as an answer

Map[Greater[#,1]&,{{0.6,1.2},{5,0.1}},{-1}]

{{False, True}, {True, False}}

yode
  • 26,686
  • 4
  • 62
  • 167