26

How would you, given a list {1, 2, 3, 4}, apply a function f to 1 and 2, then 2 and 3, etc.?

{f[1,2], f[2,3], f[3,4]}

More generally, how do you define which parts of a list you want to pass/Map/Apply to a function that takes multiple arguments?

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
Teo Sartori
  • 473
  • 3
  • 7

13 Answers13

25

Update: in version 10.2 BlockMap was added as a System context function.


If the arguments are sequential there is a function Developer`PartitionMap that does this directly, potentially saving considerable memory over Partition.

Developer`PartitionMap[f @@ # &, Range@5, 2, 1]
{f[1, 2], f[2, 3], f[3, 4], f[4, 5]}

Syntax is the same as for Partition but with the function to map inserted as the first argument. Notice in my use above that I needed Apply (short form @@) to pass the elements as arguments rather than a single list.

If the arguments are not sequental you can use Part:

list = {a, b, c, d, e}; 

parts = {{1, 2}, {4, 1, 3}, {5, 2}};

f @@ list[[#]] & /@ parts
{f[a, b], f[d, a, c], f[e, b]}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
18

You can use

f @@@ Partition[{1,2,3,4}, 2, 1]

which will give

{f[1,2], f[2,3], f[3,4]}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
17

You might first partition your list and then use Map as usual :

f[#[[1]], #[[2]]] & /@ Partition[{1,2,3,4}, 2, 1]

(* {f[1, 2], f[2, 3], f[3, 4]} *)
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
b.gates.you.know.what
  • 20,103
  • 2
  • 43
  • 84
17

Several additional alternatives:

MapThread:

MapThread[g, #] &@{Most@#, Rest@#} &@{r, s, t, u, v, w}

{g[r, s], g[s, t], g[t, u], g[u, v], g[v, w]}

or,

MapThread[g, #] &@Transpose@Partition[#, 2,1] &@{r, s, t, u, v, w}

{g[r, s], g[s, t], g[t, u], g[u, v], g[v, w]}

which allows more flexibility to specify the lists to thread over, like:

MapThread[g, #] &@Transpose@Partition[#, 3, 2, 1] &@{r, s, t, u, v, w}

{g[r, s, t], g[s, t, u], g[t, u, v], g[u, v, w]}

Inner:

With last argument set to List gives the same result as MapThread:

Inner[g, Sequence @@ #, List] &@Transpose@Partition[#, 2, 1] &@{r, s,t, u, v, w}

{g[r, s], g[s, t], g[t, u], g[u, v], g[v, w]}

Thread:

Thread[g[Most@#, Rest@#]] &@{r, s, t, u, v, w};
Thread[g[Sequence @@ #]] &@({Most@#, Rest@#} &@{r, s, t, u, v, w});
Thread[g[Sequence @@ #]] &@(Transpose@Partition[#, 2, 1] &@{r, s, t,u, v, w});

From docs on Thread:

Functions with attribute Listable are threaded automatically over lists.

Hence for Listable functions, e.g., for h in the following example:

SetAtrributes[h, Listable];
h[Sequence @@ #] &@(Transpose@Partition[#, 2, 1] &@{r, s, t, u, v, w})

gives the same result as does

Thread[h[Sequence @@ #]] &@(Transpose@Partition[#, 2, 1] &@{r, s, t, u, v, w}).

Also from docs:

MapThread takes the function and its arguments separately.

Thread evaluates the whole expression before threading.

Hence, using MapThread is "safer" as pointed out in Mr.Wizard's comments.

Timings:

Test data:

 tsts = Table[RandomInteger[1000, 1000000], {10}];

Results table (apologies for not figuring out how to apply Thread in the following):

Grid[{{"method", "timing"}, 
    {HoldForm[Thread[g[Sequence @@ #]] &@(Transpose@Partition[#, 2, 1] &)], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    Thread[g[Sequence @@ #]] &@ (Transpose@Partition[#, 2, 1] &@ tsts[[i]])][[1]], 
      {i, 1, 10}] // Mean},
    {HoldForm[Thread[g[Most@#, Rest@#]] &], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    Thread[g[Most@#, Rest@#]] &@tsts[[i]]][[1]], {i, 1, 10}] //  Mean},
    {HoldForm[MapThread[g, Transpose@Partition[#, 2, 1]] &], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    MapThread[g, Transpose@Partition[#, 2, 1]] &@tsts[[i]]][[1]], {i, 1, 10}] // Mean},
    {HoldForm[MapThread[g, {Most@#, Rest@#}] &], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    MapThread[g, {Most@#, Rest@#}] &@tsts[[i]]][[1]], {i, 1, 10}] //  Mean},
    {HoldForm[Inner[g, Sequence @@ #, List] &@{Most@#, Rest@#} &], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    Inner[g,Sequence @@ #,List] &@{Most@#,Rest@#} &@tsts[[i]]][[1]], {i, 1, 10}] // Mean}, 
    {HoldForm[Inner[g, Sequence @@ #, List] &@Transpose@Partition[#, 2, 1] &], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    Inner[g, Sequence @@ #, List] &@Transpose@Partition[#, 2, 1] &@
    tsts[[i]]][[1]], {i, 1, 10}] // Mean},
    {HoldForm[Developer`PartitionMap[g @@ # &, tsts[[i]], 2, 1]], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    Developer`PartitionMap[g @@ # &, tsts[[i]], 2, 1]][[1]], {i, 1, 10}] // Mean}, 
    {HoldForm[g @@@ Partition[tsts[[i]], 2, 1]], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    g @@@ Partition[tsts[[i]], 2, 1]][[1]], {i, 1, 10}] // Mean}, 
    {HoldForm[ g @@@ Most[{tsts[[i]], RotateLeft@tsts[[i]]}\[Transpose]]], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
    g @@@ Most[{tsts[[i]], RotateLeft@tsts[[i]]}\[Transpose]]][[1]], {i, 1, 10}] // Mean}, 
    {HoldForm[Fold[(Sow[g[#1, #2]]; #2) &, First@#, Rest@#] &@tsts[[i]]; // 
     Reap // Last], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
     Fold[(Sow[g[#1, #2]]; #2) &, First@#, Rest@#] &@tsts[[i]]; //
      Reap // Last][[1]], {i, 1, 10}] // Mean},
    {HoldForm[g[#[[1]], #[[2]]] & /@ Partition[tsts[[i]], 2, 1]], 
    Table[AbsoluteTiming[ClearSystemCache[]; 
     g[#[[1]], #[[2]]] & /@ Partition[tsts[[i]], 2, 1]][[1]], {i, 1, 10}] // Mean}}, 
    Frame -> All]

Timing results:

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
  • Probably too specific since the OP was asking "generally" but if you expand this answer to address Listable functions and discuss the performance benefits you'll heartily earn my +1. – Mr.Wizard Apr 09 '12 at 15:03
  • @Mr.Wizard I like this one, and it's the type of thing I often use as I didn't know about Developer`Partition until very recently. – rcollyer Apr 09 '12 at 15:11
  • @rcollyer I like this one a lot too (hence: "heartily") but the answer is unfinished. Thread as shown is dangerous because of evaluation order, and the most elegant an efficient possibility (with Listable functions) is neither shown nor explained. – Mr.Wizard Apr 09 '12 at 15:13
  • @Mr.Wizard How is Thread dangerous? I don't see it. I also, don't see the answer as being incomplete. Instead, I see it as not being generalizable, e.g. what if the OP wanted to expand it to sequential, overlapping triples, instead? – rcollyer Apr 09 '12 at 15:20
  • @rcollyer so f = Print; Thread[f[Most@#, Rest@#]] &@{1, 2, 3} does what you expect and desire? I say incomplete because the prime advantage to this method is performance, especially with Listable functions. If kguler doesn't add that, I will. – Mr.Wizard Apr 09 '12 at 15:36
  • 1
    @Mr.Wizard well with Listable functions neither Thread nor MapThread are necessary, e.g. Block[{f}, SetAttributes[f, Listable]; f[Most@#, Rest@#] &@{1, 2, 3}]. Setting f = Print is an interesting counter argument. I'm still parsing it. My Listable example doesn't function as expected with Print, either. – rcollyer Apr 09 '12 at 15:46
  • @rcollyer yes, Most@# * Rest@# working is my point. The problem with Thread (versus MapThread) is that f evaluates before the threading operation; this is hardly safe or robust. – Mr.Wizard Apr 09 '12 at 15:49
  • @Mr.Wizard thank you for finally being explicit. – rcollyer Apr 09 '12 at 15:50
  • @Mr.Wizard & rcollyer, thank you for constructive comments/suggestions. Will put together some test results in a moment. – kglr Apr 09 '12 at 15:50
  • @kguler I look forward to upvoting your answer. :-) – Mr.Wizard Apr 09 '12 at 15:51
  • @kguler I already upvoted it :). I like the timings chart. How did you do that? – Eiyrioü von Kauyf Apr 10 '12 at 00:59
  • @EiyrioüvonKauyf The code for that is also provided... – rm -rf Apr 10 '12 at 03:12
8

Update: A function f can be mapped to partition elements using f as the undocumented 6th argument of Partition.

Partition[{1, 2, 3, 4}, 2, 1, {1, -1}, {}, f]

{f[1, 2], f[2, 3], f[3, 4]}

Partition[{1, 2, 3, 4}, 2, 1, {1, -1}, {}, Plus]

{3, 5, 7}

Partition[Range[10], 5, 2, None, {}, Mean[{##}] &]

{3, 5, 7}

Also works with ragged partitions if f is defined for sequences of varying length:

{Partition[Range[5], 5, 2, {-1, 1}, {}],
 Partition[Range[5], 5, 2, {-1, 1}, {}, foo],
 Partition[Range[5], 5, 2, {-1, 1}, {}, Plus]} // Column // TeXForm

$\begin{array}{l} \{\{1\},\{1,2,3\},\{1,2,3,4,5\},\{3,4,5\},\{5\}\} \\ \{\text{foo}(1),\text{foo}(1,2,3),\text{foo}(1,2,3,4,5),\text{foo}(3,4,5),\text{foo}(5)\} \\ \{1,6,15,12,5\} \\ \end{array}$


Original post:

List @@ Partition[f[1, 2, 3, 4], 2, 1]

{f[1, 2], f[2, 3], f[3, 4]}

kglr
  • 394,356
  • 18
  • 477
  • 896
7

Mathematica 10 introduced MovingMap and operator forms:

MovingMap[Apply[f], Range @ 9, 2]
{f[1, 2], f[2, 3], f[3, 4], f[4, 5], f[5, 6], f[6, 7], f[7, 8], f[8, 9]}

Useful information: Mathematica periodic moving map


In Mathematica 10.1 the syntax for MovingMap changed; now you must use:

MovingMap[Apply[f], Range @ 9, 1]
{f[1, 2], f[2, 3], f[3, 4], f[4, 5], f[5, 6], f[6, 7], f[7, 8], f[8, 9]}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 1
    There's also ListCorrelate[{1, 1}, Range@9, {1, -1}, {}, Times, f] – LLlAMnYP May 12 '15 at 09:01
  • @LLlAMnYP My update is not intended to preclude that; please post that as an answer if you would like. – Mr.Wizard May 12 '15 at 09:03
  • it's on my mind right now, as I'm reflecting on a question of mine about mapping to a subsequence of a list (generalization to multidimensional lists in a different way, than suggested before). I'm surprised, it didn't show up in the answers, as it's around since v.4, but I'm reluctant to post it, when there are now several functions in v.10 that do specifically the required thing. – LLlAMnYP May 12 '15 at 09:20
  • @LLlAMnYP I see no reason not to post it; not only are backward-compatible methods of use to many people but alternative methods can often be adapted in ways that built-ins cannot. Incidentally ListCorrelate did get a mention in my answer to a more recent and related question. – Mr.Wizard May 12 '15 at 09:35
6

And yet another one:

list = Range[5];

f @@@ Most[{list, RotateLeft@list}\[Transpose]]

(*
==> {f[1, 2], f[2, 3], f[3, 4], f[4, 5]}
*)
Sjoerd C. de Vries
  • 65,815
  • 14
  • 188
  • 323
5

It's strange, that ListCorrelate has not been mentioned, according to the documentation, it has been around unchanged since v.4.0. It allows a one liner:

ListCorrelate[{1, 1}, Range@9, {1, -1}, {}, Times, f]
(* {f[1, 2], f[2, 3], f[3, 4], f[4, 5], f[5, 6], f[6, 7], f[7, 8], f[8, 9]} *)
ListConvolve[{1, 1}, Range@9, {-1, 1}, {}, Times, f]
(* {f[1, 2], f[2, 3], f[3, 4], f[4, 5], f[5, 6], f[6, 7], f[7, 8], f[8, 9]} *)

ListConvolve, as you can see, acts in a very similar manner. Their drawback is, they necessarily move along the list in steps of one. A result like

(* {f[1, 2, 3], f[3, 4, 5], f[5, 6, 7], f[7, 8, 9]} *)

does not appear to be possible(?)

LLlAMnYP
  • 11,486
  • 26
  • 65
4

I would probably use Developer`PartitionMap, but here's an approach using Fold, Reap and Sow just to demonstrate the various ways of doing the same thing:

list = {1, 2, 3, 4};
Fold[(Sow[f[#1, #2]]; #2) &, First@#, Rest@#] &@ list; // Reap // Last
(* Out[1]= {{f[1, 2], f[2, 3], f[3, 4]}} *)
rm -rf
  • 88,781
  • 21
  • 293
  • 472
2
 MapIndexed[f[#1, list[[#2[[1]] + 1]]] &, Most@list]

or

f @@ RotateLeft[list, #][[1 ;; 2]] & /@ Range[0, Length[list] - 2]
Alucard
  • 2,639
  • 13
  • 22
2
list = {1, 2, 3, 4};

1.

SequenceCases - introduced in 2015 (10.1)

SequenceCases[list, {a_, b_} :> f[a, b], Overlaps -> True]

{f[1, 2], f[2, 3], f[3, 4]}

2.

BlockMap - introduced in 2015 (10.2)

BlockMap[Apply @ f, list, 2, 1]

{f[1, 2], f[2, 3], f[3, 4]}

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

As of 2022 we have at our disposal the resource function called ThroughOperator that can do that. This is a development thanks to @Sjoerd Smit.

It was first suggested here. In the comment section under the answer @Sjoerd Smit gives motivation for its development and subsequent use for those interested. It was further used in this thread.

The main use is if we want to apply a number of functions on a list, however, we can use it in this example as well.

Flatten[ResourceFunction["ThroughOperator"][{f}] /@ 
   Partition[{1, 2, 3, 4}, 2, 1]] /. f[{a_, b_}] -> f[a, b]

{f[1, 2], f[2, 3], f[3, 4]}

Try for instance

Flatten[ResourceFunction["ThroughOperator"][{f, g, h, w}] /@ 
  Partition[{1, 2, 3, 4}, 2, 1]]
bmf
  • 15,157
  • 2
  • 26
  • 63
1

Using MapThread and Construct:

h[f_Symbol] := MapThread[Construct, {Array[f &, Length@#], Sequence @@ Transpose@#}] &;

h[f]@Partition[Range[4], 2, 1]

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

h[g]@Partition[{r, s, t, u, v, w}, 2, 1]

({g[r, s], g[s, t], g[t, u], g[u, v], g[v, w]})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44