What's the difference between setting a function's attribute as Listable and using Map? I understand that Map is more specific, the question is rather about action on single depth lists.


The main difference can been seen when dealing with list of lists. Consider the following list:

lis = {{1, 2, 3}, {3, 4, 5}, {5, 6, 7}};

Lets create a Listable function g

SetAttributes[g, Listable]

Now we Map a non-listable function f and apply the listable function g

Map[f, lis]

(* {f[{1, 2, 3}], f[{3, 4, 5}], f[{5, 6, 7}]} *)


(* {{g[1], g[2], g[3]}, {g[3], g[4], g[5]}, {g[5], g[6], g[7]}} *)

Clearly the Listable function g, continues until it's applied down to a non-list expression. Whereas Map by default applies to Level 1. One can get the same behavior with Map by using the 3rd argument (level specification):

Map[f, lis, {2}]

(* {{f[1], f[2], f[3]}, {f[3], f[4], f[5]}, {f[5], f[6], f[7]}} *)

On Single-depth lists, they both behave the same:

lis2 = {1, 2, 3, 4, 5, 6};

Map[f, lis2]

   {f[1], f[2], f[3], f[4], f[5], f[6]}
   {g[1], g[2], g[3], g[4], g[5], g[6]} 

Performance does not seem to vary much either. Consider the following functions:

SetAttributes[k, Listable];
k[x_]:= x^2 + 2x
u[x_]:= x^2 + 2x

Let's apply them to a large list:

lis3 = RandomReal[2, 10^6];
k[lis3]; // RepeatedTiming
Map[u, lis3]; // RepeatedTiming

(* {1.26, Null}    
   {1.242, Null} *)

Of course, if you are going to use Map, you're better off using a pure function since that increases performance by a lot:

Map[#^2 + 2 # &, lis3]; // RepeatedTiming

{0.065, Null}

To be fair, I should also mention that you can make a Listable pure function (see comments) that performs about the same as Map with a pure function. As Szabolcs mentioned in the comments here is an example where the Listable version appears to have no Map counterpart:

g[{1, {2, 3}, 4, h[x]}]

(* {g[1], {g[2], g[3]}, g[4], g[h[x]]} *)

So at least, that's a difference. And I'm sure one can come up with many such examples.

  • $\begingroup$ If you define k and u as #^2 + 2 # &, set k to be Listable, and then do k[lis3] vs u /@ lis3, my machine says that the former is even faster. $\endgroup$
    – march
    Apr 26 '16 at 19:55
  • $\begingroup$ @march. On mine it's slower, but I should probably mention that option too to be fair. $\endgroup$
    – RunnyKine
    Apr 26 '16 at 20:00
  • $\begingroup$ g[{1, {2, 3}, 4, f[x]}] is a good example to include too. This cannot be done with Map at all, not even by mapping at level -1. $\endgroup$
    – Szabolcs
    Apr 26 '16 at 20:48
  • $\begingroup$ @Szabolcs it comes close, oh so close. {f[1], {f[2], f[3]}, f[4], h[f[x]]} $\endgroup$
    – rcollyer
    Apr 26 '16 at 21:08
  • $\begingroup$ @Szabolcs. Thanks, I included your example. $\endgroup$
    – RunnyKine
    Apr 26 '16 at 21:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.