10
$\begingroup$

I hope this is not a silly question, since there are plenty of questions on Thread and MapThread. However, I still cannot quite understand the relationship between them. It seems MapThread can take a level argument, but Thread cannot. Thread can do something like Thread[f[{a, b, c}, x]], MapThread cannot. Why we have two of them?

Following two commands give the same results:

MapThread[f, {{a, b, c}, {x, y, z}}]
Thread[f[{a, b, c}, {x, y, z}]]
$\endgroup$
  • $\begingroup$ "MapThread works like Thread, but takes the function and arguments separately..." - straight from the documentation. They can be used to get the same results, and each has some giblets the other lacks (e.g., specifying the head to thread over in Thread). Read, understand and experiment with the examples in the documentation, everything you ever wanted to know is there. $\endgroup$ – ciao Jun 2 '15 at 4:12
  • $\begingroup$ @ciao does it means actually these two function are almost the same? It is a redundant design for convince. $\endgroup$ – Kattern Jun 2 '15 at 4:27
  • 3
    $\begingroup$ Thread has been here since V1. MapThread was added in V2, since the need to map something over sets of equal length lists is common (effectively mapping the threading over sets made up from the Nth elements of each list), made sense to add it. In addition, there are differences in evaluation - MapThread evaluates on each set as you progress, Thread attempts to evaluate the whole expression before attempting to thread it. Room (and need) for both... $\endgroup$ – ciao Jun 2 '15 at 5:16
  • $\begingroup$ @ciao An example of this is Thread[Plus[{{1, 2, 3}, {4, 5, 6}}]] vs MapThread[Plus, {{1, 2, 3}, {4, 5, 6}}]. $\endgroup$ – Chip Hurst Jun 2 '15 at 14:32
  • $\begingroup$ @ChipHurst, Shouldn't the example be "Thread[Plus[{1, 2, 3}, {4, 5, 6}]] vs MapThread[Plus, {{1, 2, 3}, {4, 5, 6}}]", which doesn't quite show what you wanted to. Perhaps Thread[Equal[{1, 2, 3}, {4, 2, 6}]] vs MapThread[Equal, {{1, 2, 3}, {4, 2, 6}}]? $\endgroup$ – Michael E2 Jun 3 '15 at 16:55
12
$\begingroup$

With one addition the difference is as you describe in your own question:

  • MapThread takes the head separately
  • MapThread only operates upon List expressions
  • MapThread does not distribute singletons
  • MapThread accepts a level specification

The first characteristic simplifies threading functions that are eager to evaluate:

f = Print;
one = {a, b, c};
two = {x, y, z};

MapThread[f, {one, two}];

Thread[f[one, two]];

ax

by

cz

{a,b,c}{x,y,z}

In the second form Print evaluates to Null giving Thread nothing to do. To make Thread work one would need to keep Print unevaluated while allowing one and two to resolve:

Block[{Print},
  Thread[f[one, two]]
];

That MapThread does not distribute singletons is something I have no explanation for. I have wished that it would work that way but I may have failed to comprehend the ramifications of that behavior. Perhaps it was determined that the interaction with level specification would be too confusing or arbitrary.

Exploration

Here is an attempt at implementing a MapThread variant with both level and head parameters that threads over singletons, based on my earlier raggedMapThread; perhaps experimentation with it will demonstrate limitations or implementation difficulties that illuminate the reason for the existing design.

distMapThread[f_, expr_, level_Integer: 1, head_: List] := 
 Apply[f, 
   Map[Thread[#, head] &, 
     Flatten[expr, List /@ Range[2, level]],
   {level - 1}],
 {level}]

An example:

distMapThread[
  foo,
  {ReplacePart[Array[a, {3, 2, 3}], {{1, 2} -> x, {3, 2} -> z}], 
   ReplacePart[Array[b, {3, 2, 3}], {2, 1} -> y]},
  3
] // MatrixForm

enter image description here

A smaller example with a different head:

distMapThread[
 foo, 
 bar[Array[a, {3, 2}, 1, bar], ReplacePart[Array[b, {3, 2}, 1, bar], 2 -> x]],
 2,
 bar
]
bar[
 bar[foo[a[1, 1], b[1, 1]], foo[a[1, 2], b[1, 2]]], 
 bar[foo[a[2, 1], x], foo[a[2, 2], x]],
 bar[foo[a[3, 1], b[3, 1]], foo[a[3, 2], b[3, 2]]]
]
| improve this answer | |
$\endgroup$
  • $\begingroup$ The example is very helpful! $\endgroup$ – Kattern Jun 4 '15 at 6:53

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.