8
$\begingroup$

Consider the lists:

list1={a,b,c};
list2={x,y,z};

I want to Thread If elementwise across the lists. I can achieve this with MapThread but cannot with Thread

In[1]:= MapThread[If[#1>#2,1,0]&,{list1,list2}]
Out[1]= {If[a>x,1,0],If[b>y,1,0],If[c>z,1,0]}

It fails when I try to do it with Thread

In[2]:= Thread[If[#1>#2,1,0]&[list1,list2]]
Out[2]= If[{a,b,c}>{x,y,z},1,0]

Academic Question

How can I perform the functionality with Thread instead of MapThread ?

$\endgroup$
3
  • $\begingroup$ Also (very similar to posted methods): Thread[If[#,1,0]]&@Thread[Greater[##]]&[list1,list2] $\endgroup$
    – user1066
    Commented Oct 1, 2022 at 3:32
  • 1
    $\begingroup$ Here's a different approach: Subtract[1, UnitStep[Subtract[list2, list1]]]. Or you can use BoolEval, which does this under the hood. $\endgroup$
    – Greg Hurst
    Commented Oct 2, 2022 at 2:41
  • $\begingroup$ Another variant, using Thread as requested: If[#1 > #2, 1, 0] &[list1, list2] //. f_?(MemberQ[_List]) :> Thread[f] $\endgroup$
    – Michael E2
    Commented Oct 2, 2022 at 12:46

5 Answers 5

12
$\begingroup$

Thread doesn't hold its arguments unevaluated. In

Thread[If[#1 > #2, 1, 0] &[list1, list2]]

the "body", If[#1 > #2, 1, 0] &[list1, list2], was evaluated immediately. That left a form with nothing for Thread to thread over.

Academic answer (one of probably many):

Thread[Inactive[If[#1 > #2, 1, 0] &][list1, list2]] // Activate
$\endgroup$
0
7
$\begingroup$

Inner is more suitable for this task then Thread.

Inner[If[#1 > #2, 1, 0] &, list1, list2, List]

{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}

$\endgroup$
2
  • $\begingroup$ (+1) Nice, @cvgmt! $\endgroup$ Commented Sep 30, 2022 at 21:44
  • $\begingroup$ @E.Chan-López Thanks! $\endgroup$
    – cvgmt
    Commented Sep 30, 2022 at 21:44
4
$\begingroup$

Just another way using MapApply:

MapApply[Function[{x, y}, If[x > y, 1, 0]], Transpose[List[list1, list2]]]
(*{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}*)

Another way using Map:

If[#[[1]] > #[[2]], 1, 0] & /@ Transpose[List[list1, list2]]
(*{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}*)

Another way using Outer:

Diagonal[Outer[If[#1 > #2, 1, 0] &, list1, list2]]
(*{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}*)

Using Thread:

If[#[[1]] > #[[2]], 1, 0] & /@ Thread[Greater[list1, list2]]
(*{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}*)

Just using Thread in a simpler way:

Thread[If[Thread@Greater[list1, list2], 1, 0]]
(*{If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}*)
$\endgroup$
2
  • $\begingroup$ The question mentioned that they know how to answer the problem with MapThread but wanted to know how to achieve the same with Thread. $\endgroup$ Commented Sep 30, 2022 at 21:30
  • $\begingroup$ Sorry, I've corrected it. :) $\endgroup$ Commented Sep 30, 2022 at 21:36
3
$\begingroup$

Using Thread:

list1 = {a, b, c};
list2 = {x, y, z};

Thread[If[Thread[#1 > #2], 1, 0] &[list1, list2]]

(*  {If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}  *)

SeedRandom[0];
Thread[If[Thread[#1 > #2], 1, 0] &[RandomReal[1, 10], 
  RandomReal[1, 10]]]

(*  {1, 0, 0, 0, 1, 1, 0, 1, 0, 1}  *)

The problem with the code

Thread[If[#1 > #2, 1, 0] &[list1, list2]]

is that, while "Thread[f[args]] 'threads' f over any lists that appear in args," there are no lists in the arguments of the code that Thread is applied to. The code that Thread receives is If[{a, b, c} > {x, y, z}, 1, 0].

If the goal is to thread a function f over lists f[list1, list2], the standard ways are to use MapThread or make the function Listable:

Function[Null, If[#1 > #2, 1, 0], Listable][list1, list2]

(*  {If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}  *)

Generic operator:

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

thread[If[#1 > #2, 1, 0] &][list1, list2]

(* {If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}  *) 

Of course, MapThread already does this, with a slightly different syntax:

MapThread[If[#1 > #2, 1, 0] &]@{list1, list2}

(*  {If[a > x, 1, 0], If[b > y, 1, 0], If[c > z, 1, 0]}  *)

While thread[f] and MapThread[f]@*List produce equivalent outputs, they are not identical computations, since Listable and mapping are implemented in different ways.

$\endgroup$
0
$\begingroup$
a = {9, 6, 7, 4, 4, 9, 9, 5, 4, 9};

b = {8, 1, 3, 3, 4, 4, 6, 6, 8, 2};

Using Boole and MapApply (new in 13.1)

Boole @* MapApply[Greater] @ Transpose[{a, b}]

{1, 1, 1, 1, 0, 1, 1, 0, 0, 1}

$\endgroup$

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.