From: Dimitris Emmanoulopoulos on
Hello

I was wondering if there is any straightforward way to bin a list into sub-lists containing those elements that full-fill a given criterion. Consider the following list

ds=
{{{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1},{6,2345,1},{7,2418,1},{8,2323,1},{9,2179,1}},{{480,23,1},{487,23,1},{470,29,1},{478,32,1},{468,25,1},{498,19,-1},{494,15,1},{496,20,1},{455,33,1},{462,27,1}},{{781,1,1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1},{716,0,-1},{794,1,1}}}

The criterion is that the sum of the second elements in each new sub-list should be at least 25?

After the re-binning we should get something like:

{{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1}}
{6,2345,1}
{7,2418,1}
{8,2323,1}
{9,2179,1}
{{480,23,1},{487,23,1}}
{470,29,1}
{478,32,1}
{468,25,1},
{498,19,-1},{494,15,1},
{496,20,1},{455,33,1}
{{462,27,1},{781,1,1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1},{716,0,-1},{794,1,1}}}

The first bin has a total of the second elements 588, the second 2345, the third 2418,...,the sixth 46, the seventh 29, …,the eleventh 53, and the last one 35.

In other words, imagine that these are the results of a counting experiment and the second element in every entry (in ds) corresponds to counts. The question is how can we re-bin the data in order to have at least 25 counts per new-bin?
Of course it is straightforward to do it using a Do-loop, but I was wondering if there is any simpler way to do it using the efficient Mathematica syntax in an “one-liner expression”.

Thanks a lot
Dimitris

From: Peter Pein on
Am Sat, 26 Jun 2010 07:10:41 +0000 (UTC)
schrieb Dimitris Emmanoulopoulos <demmanoulopoulos(a)hotmail.com>:

> Hello
>
> I was wondering if there is any straightforward way to bin a list
> into sub-lists containing those elements that full-fill a given
> criterion. Consider the following list
>
> ds=
> {{{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1},{6,2345,1},{7,2418,1},{8,2323,1},{9,2179,1}},{{480,23,1},{487,23,1},{470,29,1},{478,32,1},{468,25,1},{498,19,-1},{494,15,1},{496,20,1},{455,33,1},{462,27,1}},{{781,1,1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1},{716,0,-1},{794,1,1}}}
>
> The criterion is that the sum of the second elements in each new
> sub-list should be at least 25?
>
> After the re-binning we should get something like:
>
> {{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1}}
> {6,2345,1}
> {7,2418,1}
> {8,2323,1}
> {9,2179,1}
> {{480,23,1},{487,23,1}}
> {470,29,1}
> {478,32,1}
> {468,25,1},
> {498,19,-1},{494,15,1},
> {496,20,1},{455,33,1}
> {{462,27,1},{781,1,1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1},{716,0,-1},{794,1,1}}}
>
> The first bin has a total of the second elements 588, the second
> 2345, the third 2418,...,the sixth 46, the seventh 29, =C3=A2=E2=82=AC=C2=
=A6,the
> eleventh 53, and the last one 35.
>
> In other words, imagine that these are the results of a counting
> experiment and the second element in every entry (in ds) corresponds
> to counts. The question is how can we re-bin the data in order to
> have at least 25 counts per new-bin? Of course it is straightforward
> to do it using a Do-loop, but I was wondering if there is any simpler
> way to do it using the efficient Mathematica syntax in an
> =C3=A2=E2=82=AC=C5=93one-liner expression=C3=A2=E2=82=AC_.
>
> Thanks a lot
> Dimitris
>

Hi Dimitris,

I did not manage it in one line but at least looks like Mathematica ;-)

In[2]:= d2 = Block[
{sum = 0, lst = Flatten[ds, 1]},
lst = Map[First,
Split[
Map[{#, If[(sum += #[[2]]) >= 25, sum=0; False, True]}&, lst],
Last[#1]&],
{2}];
If[Length[lst] >= 2 && Total[Last[lst][[All, 2]]] < 25,
Join[Drop[lst, -2], {Join @@ Take[lst, -2]}],
lst]
]
Out[2]=
{
{{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1}},
{{6,2345,1}},
{{7,2418,1}},
{{8,2323,1}},
{{9,2179,1}},
{{480,23,1},{487,23,1}},
{{470,29,1}},
{{478,32,1}},
{{468,25,1}},
{{498,19,-1},{494,15,1}},
{{496,20,1},{455,33,1}},
{{462,27,1},{781,1,1},{779,1,1},{784,0,1},{778,0,1},
{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1},{716,0,-1},
{794,1,1}}
}

I guess a loop based approach would be faster in execution but I did
not try it.

Cheers,
Peter



From: Leonid Shifrin on
Hi Dimitris,

here is a solution based on repeated application of rules:

In[1] :==

Module[{temp, left},
Flatten[ds, 1] //.
{{done___temp, Shortest[x__List] /; Total[{x}[[All, 2]]] >== 25,
y___} :> {done, temp[x], y},
{done___temp, rest : {_, _, _} ..} :> {done, left[rest]}} /.
temp | left -> List]

Out[1]== {{{0, 0, 1}, {1, 0, -1}, {2, 0, -1}, {3, 0, -1}, {4, 0, -1}, {5,
588, -1}}, {{6, 2345, 1}}, {{7, 2418, 1}}, {{8, 2323, 1}}, {{9,
2179, 1}}, {{480, 23, 1}, {487, 23, 1}}, {{470, 29, 1}}, {{478, 32,
1}}, {{468, 25, 1}}, {{498, 19, -1}, {494, 15, 1}}, {{496, 20,
1}, {455, 33, 1}}, {{462, 27, 1}}, {{781, 1, 1}, {779, 1, 1}, {784,
0, 1}, {778, 0, 1}, {766, 1, -1}, {735, 1, -1}, {758,
1, -1}, {733, 2, -1}, {716, 0, -1}, {794, 1, 1}}}

Note that the last list may not satisfy your criteria and in general simply
gathers leftovers. You can convert it to a function as follows:

Clear[rebin];
rebin[binned : {{{_?NumericQ, _?NumericQ, _?NumericQ} ..} ..},
minValue_?NumericQ] :==
Module[{temp,left},
Flatten[binned,
1] //. {{done___temp,
Shortest[x__List] /; Total[{x}[[All, 2]]] >== minValue,
y___} :> {done, temp[x], y},
{done___temp, rest : {_, _, _} ..} :> {done, left[rest]}}
/. temp|left -> List];

Then you just call,

rebin[ds, 25]

Generally, this kind of problems seem to be harder to solve in a very
succinct manner in Mathematica without resorting to side effects, since in
splitting the list some non-trivial run-time information is required. For
example, you can solve the problem much easier if you allow side effects to
be used:

In[4]:==
Module[{sum == 0},
Split[Flatten[ds,
1], (sum +== #1[[2]]; If[sum >== 25, sum == 0; False, True]) &]]

Out[4]==
{{{0, 0, 1}, {1, 0, -1}, {2, 0, -1}, {3, 0, -1}, {4,
0, -1}, {5, 588, -1}}, {{6, 2345, 1}}, {{7, 2418, 1}}, {{8, 2323,
1}}, {{9, 2179, 1}}, {{480, 23, 1}, {487, 23, 1}}, {{470, 29,
1}}, {{478, 32, 1}}, {{468, 25, 1}}, {{498, 19, -1}, {494, 15,
1}}, {{496, 20, 1}, {455, 33, 1}}, {{462, 27, 1}}, {{781, 1,
1}, {779, 1, 1}, {784, 0, 1}, {778, 0, 1}, {766, 1, -1}, {735,
1, -1}, {758, 1, -1}, {733, 2, -1}, {716, 0, -1}, {794, 1, 1}}}

Hope this helps.

Regards,
Leonid


On Sat, Jun 26, 2010 at 12:10 AM, Dimitris Emmanoulopoulos <
demmanoulopoulos(a)hotmail.com> wrote:

> Hello
>
> I was wondering if there is any straightforward way to bin a list into
> sub-lists containing those elements that full-fill a given criterion.
> Consider the following list
>
> ds==
>
> {{{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1},{6,2345,1},{7,24=
18,1},{8,2323,1},{9,2179,1}},{{480,23,1},{487,23,1},{470,29,1},{478,32,1},{=
468,25,1},{498,19,-1},{494,15,1},{496,20,1},{455,33,1},{462,27,1}},{{781,1,=
1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1},{758,1,-1},{733,2,-1=
},{716,0,-1},{794,1,1}}}
>
> The criterion is that the sum of the second elements in each new sub-list
> should be at least 25?
>
> After the re-binning we should get something like:
>
> {{0,0,1},{1,0,-1},{2,0,-1},{3,0,-1},{4,0,-1},{5,588,-1}}
> {6,2345,1}
> {7,2418,1}
> {8,2323,1}
> {9,2179,1}
> {{480,23,1},{487,23,1}}
> {470,29,1}
> {478,32,1}
> {468,25,1},
> {498,19,-1},{494,15,1},
> {496,20,1},{455,33,1}
>
> {{462,27,1},{781,1,1},{779,1,1},{784,0,1},{778,0,1},{766,1,-1},{735,1,-1}=
,{758,1,-1},{733,2,-1},{716,0,-1},{794,1,1}}}
>
> The first bin has a total of the second elements 588, the second 2345, th=
e
> third 2418,...,the sixth 46, the seventh 29, =85,the eleventh 53, and the=
last
> one 35.
>
> In other words, imagine that these are the results of a counting experime=
nt
> and the second element in every entry (in ds) corresponds to counts. The
> question is how can we re-bin the data in order to have at least 25 count=
s
> per new-bin?
> Of course it is straightforward to do it using a Do-loop, but I was
> wondering if there is any simpler way to do it using the efficient
> Mathematica syntax in an =93one-liner expression=94.
>
> Thanks a lot
> Dimitris
>
>

From: Dimitris Emmanoulopoulos on
Thank you very much all for your useful replies.