# Breaking a sorted list into bins of a specified size

Can somebody please explain me the following:

If I try to split data every increase in 0.5:

list = Range[1.2, 3.2, 0.15]

{1.2, 1.35, 1.5, 1.65, 1.8, 1.95, 2.1, 2.25, 2.4, 2.55, 2.7, 2.85, 3., 3.15}


I would like to get the following:

{{1.2, 1.35, 1.5, 1.65}, { 1.8, 1.95, 2.1}, {2.25, 2.4, 2.55, 2.7}, {2.85,3., 3.15}


If I use the example given I here:

Splitting a list using SplitBy, by comparing adjacent elements

I can split either not at all

splittedlist = Split[list, (#1 < ( #2 - 0.1)) &]

{{1.2, 1.35, 1.5, 1.65, 1.8, 1.95, 2.1, 2.25, 2.4, 2.55, 2.7, 2.85, 3., 3.15}}


or I can split each of them

splittedlist = Split[list, (#1 < ( #2 - 0.5)) &]

{{1.2}, {1.35}, {1.5}, {1.65}, {1.8}, {1.95}, {2.1}, {2.25}, {2.4}, {2.55}, {2.7}, {2.85}, {3.}, {3.15}}


I found this package,

http : // www.theophys.kth.se/~phl/Mathematica/

which uses exactly this method (on 2D data, but still), why does it work in their method? Obviously, I am missing something.

I found this way of doing it,

Calculate mean of values in bins

but is this really the simplest way to split into intervals? I could of course write a loop, but I tried to not use a loop.

-
If 1.2 is at the beginning of the sublist then 2.7 should be too. Or am I wrong? – Kuba Apr 28 '14 at 21:05
Sorry, of course – majeriisli Apr 28 '14 at 21:43

This is built-in approach:

BinLists[#, {First@#, Last@# + .5, .5}] &@list

{{1.2, 1.35, 1.5, 1.65}, {1.8, 1.95, 2.1}, {2.25, 2.4, 2.55}, {2.7, 2.85, 3., 3.15}}

-
+1, this deserves more votes... – ciao Apr 28 '14 at 23:53
@rasher Thank you :) 50% to m_goldberg whose variable names rang a bell :) – Kuba Apr 29 '14 at 5:00
splitEvenly[list_List, step_] := SplitBy[list, Floor[Divide[# - First[list], step]] &]

splitEvenly[list, 0.5]
(* {{1.2, 1.35, 1.5, 1.65}, {1.8, 1.95, 2.1}, {2.25, 2.4, 2.55}, {2.7, 2.85, 3., 3.15}} *)


As Kuba already mentioned in his comment, 2.7 should be in the last sublist as it is 3 * 0.5 from the starting value.

If the starting value is not necessarily the value of the first element you could define it as:

splitEvenly[list_List, step_, start_: First[list]] :=
SplitBy[list, Floor[Divide[# - start, step]] &]


giving you an optional third argument to specify a starting value which defaults to the first value of the list.

-
The last one looks to me very elegant. Thanks everyone. Floor works magic in this context. Thanks again, as I need this to fit my background piecewise with polynomials and then subtract it from data, so one has to smooth the data. – majeriisli Apr 28 '14 at 23:10

This question is a simpler variation of each of these questions:

I will not fight it being closed as a duplicate but perhaps there is value in the clarify of the simple answers this one permits.

Showing each of the methods from my earlier answer simplified as appropriate:

### GatherBy

split[data_, width_] :=
With[{offset = Mod[First @ data, width]},
GatherBy[data, Floor[# - offset, width] &]
]

{{1.2, 1.35, 1.5, 1.65}, {1.8, 1.95, 2.1}, {2.25, 2.4, 2.55}, {2.7, 2.85, 3., 3.15}}


### BinLists

BinLists[#, {First@#, Last@# + #2, #2}] &[list, 0.5]

{{1.2, 1.35, 1.5, 1.65}, {1.8, 1.95, 2.1}, {2.25, 2.4, 2.55}, {2.7, 2.85, 3., 3.15}}


This of course is the same as Kuba's answer, but it's hard to avoid this as it is the built-in function. Unlike the first method it will return empty bins, which may or may not be desirable. (The first method can be extended to handle this case as well if required, but it makes it significantly less clean which is why I did not write it that way by default.)

-
Your motivation for providing well written/topic exchausting answers, even for basic questions, is something you deserve additional credits for. +1 ofc :) – Kuba Apr 29 '14 at 5:04
@Kuba I've actually been lacking motivation recently but I still try to put some effort into it when I do answer. Thanks for noticing and commenting. (Your answer already has my vote, of course.) – Mr.Wizard Apr 29 '14 at 16:32

I;m guessing you want the bins end points to defined as I have defined binEnds. By doing so, I got the answer you say you want.

data = Range[1.2, 3.2, 0.15];
binWidth = .5;
binEnds = Range[data[[1]], data[[-1]], binWidth];
Module[{i = 1},
Split[data, If[#2 - binEnds[[i]] <= binWidth, True, i++; False] &]]

{{1.2, 1.35, 1.5, 1.65}, {1.8, 1.95, 2.1}, {2.25, 2.4, 2.55, 2.7}, {2.85, 3., 3.15}}

-
@kuba. This is like your deleted answer, but I pre-calculate the bin end-points. – m_goldberg Apr 28 '14 at 21:39