21

MapThread works fine and dandy with rectangular list structures:

MapThread[f, {{{a, b}, {c, d}}, {{1, 2}, {3, 4}}}, 2]

{{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4]}}

But with a ragged structure, it starts complaining:

MapThread[f, {{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}}, 2]

MapThread::mptd: "Object {{a,b},{c,d,e}} at position {2, 1} in MapThread[f,{{{a,b},{c,d,e}},{{1,2},{3,4,5}}},2] has only 1 of required 2 dimensions."

whereas I'd like:

{{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}}

I can't see any obvious way to achieve a pairing of the corresponding elements, but maybe you can?

wxffles
  • 14,246
  • 1
  • 43
  • 75

9 Answers9

16

Perhaps something like this, as a more general alternative? However, without tweaking it forget about level specification

Function[Null, f[##], Listable] @@ A
Rojo
  • 42,601
  • 7
  • 96
  • 188
13

Here's a way to do it by mapping MapThread:

MapThread[f, #] & /@ Transpose[{{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}}]
(* {{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}} *)
rm -rf
  • 88,781
  • 21
  • 293
  • 472
12

It's probably bad form to answer your own question, but I did manage to get something to work while I was waiting:

myMapThread[f_, list1_, list2_, level_] := 
  Module[{s}, Function[s, 
     Reap[MapIndexed[Sow[f[#1, s[[Sequence @@ #2]]]] &, list1, {level}]][[1]]]
     [list2]];

Usage:

myMapThread[f, {{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}, 2]

{{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}}

It's quite ugly though.

wxffles
  • 14,246
  • 1
  • 43
  • 75
7
ClearAll[raggedThread]
raggedThread = Inner[Thread @* #, ##2, List] &;

Example:

raggedThread[f, {{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}]
{{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}}
kglr
  • 394,356
  • 18
  • 477
  • 896
6
MapThread[f, lst[[1 ;; 2, #]]] & /@ {1, 2}

gives

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

If

lst2 = {{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}, {{aa, bb}, {cc, dd, ee}}};
MapThread[f, lst2[[1 ;; 3, #]]] & /@ {1, 2}

gives

(*{{f[a, 1, aa], f[b, 2, bb]}, {f[c, 3, cc], f[d, 4, dd], f[e, 5, ee]}}*)
user1066
  • 17,923
  • 3
  • 31
  • 49
2
x = {{a, b}, {c, d, e}};
y = {{1, 2}, {3, 4, 5}};

MapApply[f] /@ Transpose /@ Transpose[{x, y}]

{{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}}

eldo
  • 67,911
  • 5
  • 60
  • 168
1

Using the third argument of GroupBy to cover the ragged array case:

myMapThread[f_, list_] := 
If[TensorQ[list], f @@@ # &@*Thread /@ Transpose@list, 
Values[GroupBy[Catenate[list], Length, f @@@ # &@*Thread]]]

Testing myMapThread:

list1 = {{{a, b}, {c, d}}, {{1, 2}, {3, 4}}};
list2 = {{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}};

myMapThread[f, list1]

({{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4]}})

myMapThread[f, list2]

({{f[a, 1], f[b, 2]}, {f[c, 3], f[d, 4], f[e, 5]}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
0
threadRagged = Apply[#, Flatten[{##2}, {{2}, {3}}], {2}] &;

Examples:

{x, y} = {{{a, b}, {c, d, e}}, y = {{1, 2}, {3, 4, 5}}};

threadRagged[f, x, y]

{{f[a, 1], f[b, 2]},   
 {f[c, 3], f[d, 4], f[e, 5]}}
lst2 = {{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}, {{aa, bb}, {cc, dd, ee}}};

threadRagged[F, ## & @@ lst2]

 {{F[a, 1, aa], F[b, 2, bb]},   
  {F[c, 3, cc], F[d, 4, dd], F[e, 5, ee]}}
kglr
  • 394,356
  • 18
  • 477
  • 896
0
threadTwice = Map[Thread]@Thread[#@##2, List, Length @ {##2}] &;

Examples:

{x, y} = {{{a, b}, {c, d, e}}, y = {{1, 2}, {3, 4, 5}}};

threadTwice[f, x, y]

 {{f[a, 1], f[b, 2]},   
  {f[c, 3], f[d, 4], f[e, 5]}}
lst2 = {{{a, b}, {c, d, e}}, {{1, 2}, {3, 4, 5}}, {{aa, bb}, {cc, dd, ee}}};

threadTwice[f, ## & @@ lst2]

{{f[a, 1, aa], f[b, 2, bb]},   
 {f[c, 3, cc], f[d, 4, dd], f[e, 5, ee]}}
kglr
  • 394,356
  • 18
  • 477
  • 896