Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
1  
If 1.2 is at the beginning of the sublist then 2.7 should be too. Or am I wrong? –  Kuba Apr 28 at 21:05
    
Sorry, of course –  majeriisli Apr 28 at 21:43

4 Answers 4

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}}
share|improve this answer
    
+1, this deserves more votes... –  rasher Apr 28 at 23:53
    
@rasher Thank you :) 50% to m_goldberg whose variable names rang a bell :) –  Kuba Apr 29 at 5:00

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.)

share|improve this answer
    
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 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 at 16:32
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.

share|improve this answer
    
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 at 23:10

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}}
share|improve this answer
    
@kuba. This is like your deleted answer, but I pre-calculate the bin end-points. –  m_goldberg Apr 28 at 21:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.