12
votes

I want to archive:

Map2[f,{a,b,c,d}]
{f[a,b], f[b,c], f[c,d]}

But for some reason, I can only think of iterative approaches.

What's the functional way?

Edit:

Use of this, was to generate graph examples. If number list is given, following generates the graph of what it would mean, to sequentially visit all the nodes.

For example:

Map2 = # @@@ Partition[#2, 2, 1] &;
MG[elems_] := Graph[Map2[DirectedEdge, elems]]
nrs = RandomInteger[{1, 15}, 20]
MG[nrs]

{10,13,9,7,13,3,5,1,15,10,15,6,14,3,1,2,11,4,8,5}

Radial layout:

enter image description here

6
@d00b it must be; Graph is not in v7. - Mr.Wizard
@d00b: Yes, this use case is for Mathematica 8. Although note, that question itself is not version specific. All the more reason, to appreciate good answers. - Margus

6 Answers

11
votes

Most simply:

Map2 = # @@@ Partition[#2, 2, 1] &;

Or, possibly using less memory, but running a bit slower:

Map2[f_, lst_] := Developer`PartitionMap[f @@ # &, lst, 2, 1]

Also, be aware of Differences and Accumulate, which are related.


Other ways:

Inner[#, Most@#2, Rest@#2, List] &

Notice that in this one List could be a different function.

MapThread[#, {Most@#2, Rest@#2}] &

Most@MapThread[#, {#2, RotateLeft@#2}] &

Rest@MapThread[#, {RotateRight@#2, #2}] &

Table[# @@ #2[[i ;; i + 1]], {i, Length@#2 - 1}] &

Now, the timings. I will make use of Timo's timeAvg.

f1 = # @@@ Partition[#2, 2, 1] &;
f2[f_, lst_] := Developer`PartitionMap[f @@ # &, lst, 2, 1]
f3 = Inner[#, Most@#2, Rest@#2, List] &;
f4 = MapThread[#, {Most@#2, Rest@#2}] &;
f5 = Most@MapThread[#, {#2, RotateLeft@#2}] &;
f6 = Table[# @@ #2[[i ;; i + 1]], {i, Length@#2 - 1}] &;

timings = 
  Table[
   list = RandomReal[99, 10^i];
   func = Plus;
   timeAvg[#[func, list]] & /@ {f1, f2, f3, f4, f5, f6},
   {i, 6}
  ];

TableForm[timings, 
 TableHeadings -> {10^Range@6, {"f1", "f2", "f3", "f4", "f5", "f6"}}]

ListLogPlot[timings\[Transpose], Joined -> True]

enter image description here

enter image description here

The numbers on the left side of the table are the length of the list of real numbers for each run.

Note that the graph is logarithmic.

Here are the bytes of memory used while processing the longest list (1,000,000):

enter image description here


After doing the timings above, I found I can make f6 faster by eliminating Apply (@@). It is now clearly the fastest on longer lists. I will not add it to the table above because that is already wide enough, but here is the function and its timings:

f7 = Table[#2[[i]] ~#~ #2[[i + 1]], {i, Length@#2 - 1}] &;

enter image description here

9
votes

As explained in the Mathematica cookbook mapping a function over a moving sublist can be elegantly solved with the ListConvole function:

Map2[f_, l_List] := ListConvolve[{1, 1}, l, {-1, 1}, {}, #2 &, f]

In[11]:= Map2[f, {a, b, c, d}]
Out[11]= {f[a, b], f[b, c], f[c, d]}

Mr.Wizard here, adding comparative timings as requested by sakra.

enter image description here

enter image description here

7
votes

I like:

Map2[f_, l_List]:= MapThread[f, {Most@l, Rest@l}]

In[988]:= Map2[f,{a,b,c,d}]
Out[988]= {f[a,b],f[b,c],f[c,d]}
6
votes

I recently re-read your question and saw your Graph[ ] application.

I think the natural way to do that is:

f[l_] := Graph[Thread[Most@l -> Rest@l]]

So

f[{10, 13, 9, 7, 13, 3, 5, 1, 15, 10, 15, 6, 14, 3, 1, 2, 11, 4, 8, 5}]  

enter image description here

2
votes

Following belisarius' lead, and addressing your Graph application, this should be a little faster:

f = Inner[Rule, Most@#, Rest@#, Composition[Graph, List]] &;
0
votes

Wow, I saw the other solutions and they seem quite complex and obfuscate. This is a lot simpler to understand, at least if you like a more functional approach:

MapApplyImpl[fun_] := Function[{args}, Apply[fun, args]]
MapApply[fun_, argList_] := Map[MapApplyImpl[fun], argList]

and a usage example:

ff := Function[{t, phi}, t*phi]
MapApply[ff, {{0, Pi/4}, {(Pi/4)/(10^3) , 0}, {(2*Pi/(10^3)), 
   Pi/4}}]