I have a nested list:

list = {1, 2, {3, 4}, f[a], {2, h[b]}}

I would like to apply a function g to all elements of the nested list (starting from top to bottom) that are not lists themselves. That is, I would like to obtain:

{g[1], g[2], {g[3], g[4]},  g[f[a]], {g[2], g[h[b]]}}

(Using Map[g, list, {-1}] does not work, as it maps g inside f and h)

The alternative I have ended up using is the following function:

mapAtLeavesOfList[g_, x_List] := Map[mapAtLeavesOfList[g, #] &, x]
mapAtLeavesOfList[g_, x_] := g[x]

mapAtLeavesOfList[g, list]
=> {g[1], g[2], {g[3], g[4]}, g[f[a]], {g[2], g[h[b]]}}

Any better suggestions?

  • $\begingroup$ This feels like a duplicate to me. Does anyone know what I may be remembering? $\endgroup$ – Mr.Wizard Jan 5 '13 at 4:07

Contrary to what the title claims, your example shows that do not want to map at the "maximum depth" of the list, but rather, merely onto the elements of a List that are not lists themselves. I think you're over complicating things with your definition of mapAtLeavesOfList.

The solution is as simple as:

g[a_List] := g /@ a

(* {g[1], g[2], {g[3], g[4]}, g[f[a]], {g[2], g[h[b]]}} *)

If you want to use g as a blackbox function, the following should work:

    mapg[a_List] := mapg /@ a;
    mapg@list /. mapg -> g

or even:

    g[a_List] := g /@ a;

The above solution temporarily modifies g to make it listable using Block and once outside the Block, the original definition of g kicks in.

You can also set the Listable attribute for g as in Leonid's answer.

| improve this answer | |
  • $\begingroup$ In the spirit of your last suggestion, one could also do something like Block[{g}, g[list] //. x_g :> Thread[x]] $\endgroup$ – Leonid Shifrin Jan 5 '13 at 1:19
  • $\begingroup$ Thanks. I have changed the title to better reflect the question. $\endgroup$ – ecoxlinux Jan 5 '13 at 1:28
  • $\begingroup$ @ecoxlinux But the title still misses the point - what you ask is not mapping on leaves, you rather ask to thread over the lists top to bottom until non-lists are encountered. $\endgroup$ – Leonid Shifrin Jan 5 '13 at 1:34
  • $\begingroup$ Thanks to both of you (leonid and hypnotoad). Hypnotoad, I was indeed overcomplicating the issue. $\endgroup$ – ecoxlinux Jan 5 '13 at 2:49

A few other alternatives: either you can make g itself a Listable function by executing SetAttributes[g,Listable] (assuming that g is a symbol), or you can do something like this:

Function[Null, g[#], Listable][list]

where I don't make any assumptions on g (which may be a symbol but may be something else).

Note that there are subtle differences between setting g Listable and defining g[a_List] := g /@ a. The latter method is less general in two respects. First, you may not be able to add a new definition, for whatever reason. Second, this won't work if g carries Hold - attributes (HoldAll or HoldFirst) - because they will prevent the pattern g[a_List] from matching, if you pass a variable such as list. The methods based on Listable attribute are free from this particular limitation.

| improve this answer | |
  • $\begingroup$ @Rojo Yes, you are right. Will edit. $\endgroup$ – Leonid Shifrin Jan 5 '13 at 21:28

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.