1
$\begingroup$

If I had a dataset such as:

s={{1,1.1,1},{2,1.2,2},{1,2.3,1},{3,2.2,2},{1,3.5,1},{4,3.6,2},{1,4.2,3},{2,4.4,1}}

I want to gather sublists based on the 2nd term of each sublist, such that first group has 2nd term of each sublists between 0 and 2, the second group has 2nd term of each sublists between 2 and 3.7, the third group has 2nd term of each sublists between 3.7 and 5. My output should look like this:

output:= {{{1,1.1,1},{2,1.2,2}},{{1,2.3,1},{3,2.2,2},{1,3.5,1},{4,3.6,2}},{{1,4.2,3},{2,4.4,1}}}

I suspect it should be something of the sort:

r = {0, 2, 3.7, 5};
GatherBy[s, {#[[2]] > #1 &, #[[2]] < #2}] & /@ MapThread[Most@r, Rest@r]
$\endgroup$
5
  • 4
    $\begingroup$ I mean, GatherBy[s, #[[2]] < 2.5 &] does what you want. Can you provide an example for which that fails so that we have a better idea of what you're trying to do? $\endgroup$
    – march
    Commented Sep 20, 2016 at 5:04
  • $\begingroup$ if there are more than 2 groups, then I need to define more conditions. $\endgroup$
    – brama
    Commented Sep 20, 2016 at 10:55
  • 1
    $\begingroup$ @brama it is a different question then. $\endgroup$
    – Kuba
    Commented Sep 20, 2016 at 11:16
  • 1
    $\begingroup$ possible duplicate: mathematica.stackexchange.com/q/120696/121 $\endgroup$
    – Mr.Wizard
    Commented Sep 20, 2016 at 13:45
  • $\begingroup$ Related: mathematica.stackexchange.com/q/50559/121 $\endgroup$
    – Mr.Wizard
    Commented Sep 21, 2016 at 6:56

3 Answers 3

4
$\begingroup$

Define your division markers,

divisions = {2, 3.7, 5}

Then use GatherBy and use the sorted position of an element in this list as the gathering function

GatherBy[s, Position[Sort[Append[divisions, #[[2]]]], #[[2]]] &]


(* {{{1, 1.1, 1}, {2, 1.2, 2}}, {{1, 2.3, 1}, {3, 2.2, 2}, {1, 
       3.5, 1}, {4, 3.6, 2}}, {{1, 4.2, 3}, {2, 4.4, 1}}} *)
$\endgroup$
1
  • $\begingroup$ Also GatherBy[s, First@Ordering@Ordering@Prepend[r, #[[2]]] &] $\endgroup$ Commented Sep 21, 2016 at 9:33
1
$\begingroup$

Maybe something like this

ineqFu[a_, b_, max_, expr_, data_] :=
 If[
  a == 0,
  expr <= data[[b]]
  ,
  If[
   b == max,
   data[[a]] < expr
   ,
   data[[a]] < expr <= data[[b]]
   ]
  ]

max = Length@bounds + 1;
tokenizedIneqs = 
  ineqFu[##, max, token, r] & @@@ 
   Partition[Range[0, max], 2, 1];
funkyTown =
  Which @@@
   (Function@
      Evaluate[Riffle[tokenizedIneqs, Range[max]]] /. 
     token :> #[[2]]);
result = GatherBy[s, funkyTown];

We then have

result === output

True

$\endgroup$
6
  • $\begingroup$ Sorry for the confusion, but what I meant by my earlier comment is that if the dataset were larger and if there are multiple values for the #[[2]] (such that the bins are 0 to 2.5, 2.5 to 4.5, 4.5 to 6.2, 6.2 to 7.4, and so on), how can I gather for the above bins? so my solution will be {{{x11,1.1,y11},{x21,2,y21},...{xn1,2.4,yn1}},{{x12,2.6,y12},{x22,2.8,y22},...{xn2,4.4,yn2}},..{{x1m,6.3,y1m},{x2m,6.8,y2m},...{xnm,7.3,ynm}}} $\endgroup$
    – brama
    Commented Sep 20, 2016 at 11:57
  • $\begingroup$ @brama If I understand you correctly (big if), then my code does what you ask. Note that the my variable result stores the result/output/solution, the reason I show the output of result[[All,All,2]] instead is because it is easier for me to see from this that the code works. $\endgroup$ Commented Sep 20, 2016 at 12:38
  • $\begingroup$ I am not afraid that's not what I want. Please see the edited question. Hope it is clearer. $\endgroup$
    – brama
    Commented Sep 20, 2016 at 12:51
  • $\begingroup$ @brama I hope I did not confuse you earlier by slightly adapting the input (data/s). But without adapting my code, the result of my code equals the desired output. $\endgroup$ Commented Sep 20, 2016 at 13:06
  • $\begingroup$ @brama I see that you have edited your data (s), but you have not made your output correspond to this yet. I mean there is a 1 in output that should be a 1.2. $\endgroup$ Commented Sep 20, 2016 at 13:07
1
$\begingroup$
s = {{1, 1.1, 1}, {2, 1.2, 2}, {1, 2.3, 1}, {3, 2.2, 2}, {1, 3.5, 1}, {4, 3.6, 2}, {1, 4.2, 3}, {2, 4.4, 1}};
divisions = {2, 3.7, 5};

condGather[list_, divi_] := 
 Block[{second, f, s = list, divisions = divi, els, ord},
  second := #[[2]] &;
  f[x_] := Block[{divs, part, int, cond, which},
    divs = Insert[Insert[divisions, -Infinity, 1], Infinity, -1];
    part = Partition[divs, 2, 1];
    int = IntervalMemberQ[#1, x] & /@ Interval /@ part;
    cond = Riffle[int, Range[Length@divs - 1]];
    which = Which[##] & @@ cond
    ];
  els = f /@ second /@ s;
  ord = Length /@ SplitBy[els, Max];
  FoldPairList[TakeDrop, s, ord]
  ]

condGather[s, divisions]

{{{1, 1.1, 1}, {2, 1.2, 2}}, {{1, 2.3, 1}, {3, 2.2, 2}, {1, 3.5, 1}, {4, 3.6, 2}}, {{1, 4.2, 3}, {2, 4.4, 1}}}

TableForm[%, TableDepth -> 2]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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