# Finding the midpoints of an ordered list of numbers

Suppose that I have an ordered list of numbers. The numbers in the list may be evenly spaced, but they may not be. Here are two examples, list1 and list2:

list1 = {0, 0.2, 0.4, 0.6, 0.8, 1};
list2 = {0, 0.3, 0.4, 0.7, 0.9, 1};


I would like to write a function to determine the midpoints (or "midvalues"). So, I would like to write fun such that with the following input I will obtain the following output:

fun[list1]
fun[list2]

{0.1, 0.3, 0.5, 0.7, 0.9}
{0.15, 0.35, 0.55, 0.8, 0.95}


Is there any built-in way to do this in Mathematica 8? I am looking for a simple method. I came up with the following, which seems to work fine, but I am afraid I may be overcomplicating it:

midpoint[a_, b_] := (a + b)/2
fun[list_List] := Map[Apply[midpoint, #] &, Partition[list, 2, 1]]


where

fun[list1]
fun[list2]


gives

{0.1, 0.3, 0.5, 0.7, 0.9}
{0.15, 0.35, 0.55, 0.8, 0.95}


Do you have any suggestions to make this simpler?

MovingAverage will do the job.

MovingAverage[list1, 2]


(* {0.1, 0.3, 0.5, 0.7, 0.9} *)

MovingAverage[list2, 2]


(* {0.15, 0.35, 0.55, 0.8, 0.95} *)

• Beat me to it. +1 Commented Aug 1, 2013 at 15:46

Since I missed posting MovingAverage, here's the manual way:

midpoints = Mean @ {Most[#], Rest[#]} &;

midpoints /@ {list1, list2}

{{0.1, 0.3, 0.5, 0.7, 0.9}, {0.15, 0.35, 0.55, 0.8, 0.95}}


One could also use ListCorrelate which I believe is equivalent to MovingAverage:

ListCorrelate[{0.5, 0.5}, #] & /@ {list1, list2}

{{0.1, 0.3, 0.5, 0.7, 0.9}, {0.15, 0.35, 0.55, 0.8, 0.95}}


In this case the "manual" way is actually faster (v7 timings):

big = Sort @ RandomReal[99, {1500000}];

time = Function[x, First @ Timing @ Do[x, {100}] / 100, HoldAll];

MovingAverage[big, 2]          // time
ListCorrelate[{0.5, 0.5}, big] // time
midpoints[big]                 // time


0.04508

0.04586

0.01529

RK recommended: {0.5, 0.5}.{Most[#], Rest[#]} & and this is faster still:

{0.5, 0.5}.{Most[#], Rest[#]} &@big // time


0.01201

Here are the timings in V9 (Michael E2's machine, different base speed).

MovingAverage[big, 2] // time
midpoints[big] // time
ListCorrelate[{0.5, 0.5}, big] // time


0.02919396

0.04955550

0.02882864

• +1. As a matter of fact, at some point (that was probably for V8) I have implemented several financial indicators and then compared the speed to the corresponding built-in ones. I was surprised to have found that for some of them, my hand-written ones (compiled to C) were an order of magnitude faster than those built-ins. It may have changed by now, I did not check for a long time. Commented Aug 1, 2013 at 15:55
• In my v9 MovingAverage is about twice as fast as your midpoints. ListCorrelate is between them. +1 anyway! Commented Aug 1, 2013 at 16:02
• It's appears to be useful to be aware of the timing. +1 Commented Aug 1, 2013 at 16:02
• Here is the order on my computer: ListCorrelate (0.02796875), MovingAverage (0.02906250), midpoints (0.03531250). V9.0.1 Windows 8.1 x64 Commented Aug 1, 2013 at 16:13
• Similar to midpoints would be {.5,.5}.{Most@#,Rest@#}& or .5(Most@#+Rest@#)&. Commented Aug 1, 2013 at 19:59

Another way:

midpoints[list_] := Median /@ Partition[list, 2, 1]

• FYI: Mean appears to be somewhat faster than Median here, at least in v7. Commented Aug 1, 2013 at 16:11

First create partitions,

par = Partition[list1, 2, 1]


Than find Median for each sublist as

Table[Median[par[[i]]], {i, 1, Length[par]}]


gives {0.1, 0.3, 0.5, 0.7, 0.9}

Similarly for second list.

• It is simpler to use /@ as Anon did, but if you prefer Table you can use this shorter form: Table[Median[i], {i, par}]. (Case #2 here). Also I don't know why you are using DeleteDuplicates. Commented Aug 1, 2013 at 16:44
• @Mr.Wizard: Thanks for pointing out,actually I was trying something else and it appended the list, and I carried on with same list. I have corrected it. Commented Aug 1, 2013 at 17:12

In Mathematica 10.2 this can also be achieved with BlockMap:

list1 = {0, 0.2, 0.4, 0.6, 0.8, 1};
list2 = {0, 0.3, 0.4, 0.7, 0.9, 1};


Then:

BlockMap[Mean, list1, 2, 1] (* gives: {0.1, 0.3, 0.5, 0.7, 0.9} *)


And:

BlockMap[Mean, list2, 2, 1] (* gives: {0.15, 0.35, 0.55, 0.8, 0.95} *)

• Finally PartitionMap[] is ready for primetime… :) Commented Jul 17, 2015 at 0:17

MovingAverage is probably the way to go. But since Suba already beat me to it. Here is another way using pure functions:

fun[x_List] := (#1 + #2)/2 & @@@ Partition[x, 2, 1]

fun /@ {list1, list2}


{{0.1, 0.3, 0.5, 0.7, 0.9}, {0.15, 0.35, 0.55, 0.8, 0.95}}

out of the box..

Rest@First@ImageData@
ImageFilter[Mean@First@# &, Image[{#}], {{0, 0}, {1, 0}}]  &@ list1


ugly as it is i suspect it performs pretty well.. <-Edit wrong its really bad..oh well..

Inspired by the 'out of the box' response by george2079, here is another solution that is based on a moving average filter.

ssm = StateSpaceModel[y[k] == (u[k] + u[k + 1])/2, y[k], u[k], y[k], k];

OutputResponse[ssm, list1]
(* {{0.1, 0.3, 0.5, 0.7, 0.9}} *)

OutputResponse[ssm, list2]
(* {{0.15, 0.35, 0.55, 0.8, 0.95}} *)


Although the OP was looking for a simple method, I'm thinking this would add to the variety.