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$
  • 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 Sep 20 '16 at 5:04
  • $\begingroup$ if there are more than 2 groups, then I need to define more conditions. $\endgroup$ – brama Sep 20 '16 at 10:55
  • 1
    $\begingroup$ @brama it is a different question then. $\endgroup$ – Kuba Sep 20 '16 at 11:16
  • 1
    $\begingroup$ possible duplicate: mathematica.stackexchange.com/q/120696/121 $\endgroup$ – Mr.Wizard Sep 20 '16 at 13:45
  • $\begingroup$ Related: mathematica.stackexchange.com/q/50559/121 $\endgroup$ – Mr.Wizard Sep 21 '16 at 6:56
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$
  • $\begingroup$ Also GatherBy[s, First@Ordering@Ordering@Prepend[r, #[[2]]] &] $\endgroup$ – Jacob Akkerboom Sep 21 '16 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$
  • $\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 Sep 20 '16 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$ – Jacob Akkerboom Sep 20 '16 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 Sep 20 '16 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$ – Jacob Akkerboom Sep 20 '16 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$ – Jacob Akkerboom Sep 20 '16 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, privacy policy and cookie policy

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