13
$\begingroup$

From the documentation, Thread's behavior on functions where the first parameter is a List and the second is an atomic expression, is this:

Thread[f[{a, b, c}, x]] 

(* {f[a, x], f[b, x], f[c, x]} *)

If the second argument of 'f' is not atomic, it is possible to thread over its first argument {a,b,c} while treating the 2nd argument as if it were atomic? For example, consider:

M = Table[i + j, {i, 1, 3}, {j, 1, 2}]

(* {{2, 3}, {3, 4}, {4, 5}} *)

Then,

Thread[f[{a, b, c}, M]]

(* {f[a, {2, 3}], f[b, {3, 4}], f[c, {4, 5}]} *)

This is understandable because M is not atomic so For example:

g[p_, M_ /; Dimensions[M] == {3, 2}] := {p, M}

Threading over g Doesn't work as intended:

Thread[g[{a, b, c}, M]]

(* {{a, {2, 3}}, {b, {3, 4}}, {c, {4, 5}}} *)

Worse still, the result above is due to a coincidence: Length@M==3. If this is not the case, Thread returns an error:

Thread::tdlen: Objects of unequal length in f[{a,b,c},{{2,3,4,5},{3,4,5,6}}] cannot be combined. >>

I've also considered wrapping M in some variation of Hold, but none yield atomic expressions. Is there a way to force Thread to treat the 2nd argument of the function as atomic?

The ultimate goal is to SetAttributes of the function to Listable.

$\endgroup$
11
  • $\begingroup$ But ... what is your intended result? ... f[#, M] & /@ {a, b, c} ? $\endgroup$ Commented Aug 25, 2012 at 21:32
  • $\begingroup$ @Verde, it should handle both f[#, M] & /@ {a, b, c} and f[#,M]& @ a. $\endgroup$ Commented Aug 25, 2012 at 21:40
  • 1
    $\begingroup$ I'm really not quite sure what you are trying to achieve but doesn't ReleaseHold@Thread[f[{a, b, c}, Hold@M]] do what you want? $\endgroup$
    – sebhofer
    Commented Aug 25, 2012 at 21:45
  • 1
    $\begingroup$ If I understand the question correctly, I gave explicit solutions here and here, where I also explain the solutions in detail. $\endgroup$ Commented Aug 25, 2012 at 21:55
  • 1
    $\begingroup$ @Mr.Wizard The question does not strike me as being asked narrowly about Thread. The goal seems to thread a function over a list in a certain way, and Thread was just used as a seemingly most straightforward way to obtain the desired result. At least, this is how I interpreted it from the start. $\endgroup$ Commented Aug 25, 2012 at 22:41

4 Answers 4

10
$\begingroup$

I will reproduce two solutions from my book, one using Listable SubValues described here:

listThread[f_, x_, y_] :=
  Module[{auxf},
   SetAttributes[auxf, Listable];
   auxf[t_][z_] := f[t, z];
   Through[auxf[x][y]]];

and another one using pure functions with Listable attribute, described here:

halfListable[f_, x_, y_] := Function[t, f[t, y], Listable][x]

Here is an example:

listThread[f, {1, 2}, {3, 4, 5}]
halfListable[f, {1, 2}, {3, 4, 5}]

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

More explanations can be found in the linked sections of the book.

$\endgroup$
3
  • $\begingroup$ Thank you Leonid - so far this looks like the best hope, I will likely accept shortly (still looking through your web site) though I was hoping to avoid custom functions. Could WRI have implemented a Level option functionality for Listable to achieve this? $\endgroup$ Commented Aug 25, 2012 at 22:29
  • 2
    $\begingroup$ @alancalvitti The probem is that Listable is an attribute, not a function. As such, it is wired quite deeply into the evaluation sequence. And evaluator does not have any tuning parameters, it is not even clear how you can define such parameters locally (so that they will apply to a specific head in a given place of code). $\endgroup$ Commented Aug 25, 2012 at 22:35
  • $\begingroup$ @alancalvitti Thanks for the accept. It's been a while :-). $\endgroup$ Commented Feb 19, 2013 at 19:56
7
$\begingroup$

Does this work as desired?

Thread[Unevaluated[f[{a, b, c}, M]]]
{f[a, {{2, 3}, {3, 4}, {4, 5}}],
 f[b, {{2, 3}, {3, 4}, {4, 5}}], 
 f[c, {{2, 3}, {3, 4}, {4, 5}}]}

Since apparently I was just being obstinate regarding the focus of this question I shall give in and address the extension of this behavior to a pseudo-Listable function. I still find the question underspecified in that interpretation.

ClearAll[f, a, b, c, m]

SetAttributes[f, HoldAll]
x : f[___, _List, ___] := Thread@Unevaluated@x
f[other___] := {other}

Now:

m = Table[i + j, {i, 1, 3}, {j, 1, 2}];

f[{a, b, c}, m]

f[m, {a, b, c}]
{{a, {{2, 3}, {3, 4}, {4, 5}}}, {b, {{2, 3}, {3, 4}, {4, 5}}}, {c, {{2, 3}, {3, 4}, {4, 5}}}}

{{{{2, 3}, {3, 4}, {4, 5}}, a}, {{{2, 3}, {3, 4}, {4, 5}}, b}, {{{2, 3}, {3, 4}, {4, 5}}, c}}
$\endgroup$
12
  • $\begingroup$ Nicer than my suggestion (actually the correct way to do it) but I don't think it will satisfy the OP $\endgroup$
    – sebhofer
    Commented Aug 25, 2012 at 22:06
  • $\begingroup$ @sebhofer Thanks; why not? $\endgroup$
    – Mr.Wizard
    Commented Aug 25, 2012 at 22:07
  • $\begingroup$ If I understand correctly the OP wants a function with Listable which does exactly this without using Thread or such... That's what I gather from the comment above. Not totally sure though. $\endgroup$
    – sebhofer
    Commented Aug 25, 2012 at 22:09
  • $\begingroup$ @sebhofer Then a new question is required as this one is clearly about Thread. (Final line notwithstanding.) $\endgroup$
    – Mr.Wizard
    Commented Aug 25, 2012 at 22:12
  • 1
    $\begingroup$ @alancalvitti It does so if f is Listable, otherwise it returns the desired result. $\endgroup$
    – sebhofer
    Commented Aug 25, 2012 at 22:31
5
$\begingroup$

How about:

ClearAll[f];
Thread[f[{a, b, c}, M], List, 1]
(* {f[a, {{2, 3}, {3, 4}, {4, 5}}], f[b, {{2, 3}, {3, 4}, {4, 5}}], 
   f[c, {{2, 3}, {3, 4}, {4, 5}}]}*)


Thread[g[{a, b, c}, M], List, 1]  // Grid

enter image description here

More related examples in Scope >> Sequence Specifications in docs >> Thread

$\endgroup$
13
  • $\begingroup$ +1 because this is useful information and the question is not well defined, but I interpret that the solution should also handle f[M, {a, b, c}] and this, as written, does not. $\endgroup$
    – Mr.Wizard
    Commented Aug 25, 2012 at 22:25
  • $\begingroup$ I am mistaken, it does! Thread[f[M, {a, b, c}], List, {2}] (For some reason I didn't think that worked.) $\endgroup$
    – Mr.Wizard
    Commented Aug 25, 2012 at 22:27
  • $\begingroup$ Very nice. Is there any way to make Listable work with these options? $\endgroup$ Commented Aug 25, 2012 at 22:35
  • $\begingroup$ @alancalvitti, in effect you want to change the behavior of the attribute Listable to thread over selected arguments? I would defer to Leonid/Rojo/... on whether this is possible/advisable:) $\endgroup$
    – kglr
    Commented Aug 25, 2012 at 23:06
  • $\begingroup$ alan, btw just noticed that @Leonid's answer and comment already adresses this question. $\endgroup$
    – kglr
    Commented Aug 25, 2012 at 23:18
2
$\begingroup$

The following works when f is Listable and has a definition.

M = Table[i + j, {i, 1, 3}, {j, 1, 2}];
SetAttributes[f,Listable]  
f[x_,y_]:={x,y}   
f[{a,b,c},Unevaluated@M]  
$\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.