1
$\begingroup$

I have a list and would like to group it into sublists using a couple rules.

First rule: the date difference between sequential elements is less than 3. Second Rule: the total of the second elements can't be greater than 10.

list={{{2003, 8, 16, 0, 0, 0.}, 7}, {{2003, 8, 17, 0, 0, 0.}, 3}, {{2003, 8, 23, 0, 0, 0.}, 8}, {{2003, 8, 24, 0, 0, 0.}, 2}, {{2003, 8, 25, 0, 0, 0.}, 1}, {{2003, 8, 26, 0, 0, 0.}, 4}, {{2003, 8, 27, 0, 0, 0.}, 3}, {{2003, 8, 30, 0, 0, 0.}, 8}, {{2003, 8, 31, 0, 0, 0.}, 2}, {{2003, 9, 13, 0, 0, 0.}, 7}, {{2003, 9, 14, 0, 0, 0.}, 2}, {{2003, 9, 15, 0, 0, 0.}, 1}, {{2003, 9, 20, 0, 0, 0.}, 8}, {{2003, 9, 21, 0, 0, 0.}, 2}, {{2003, 9, 26, 0, 0, 0.}, 1}, {{2003, 9, 27, 0, 0, 0.}, 5}, {{2003, 9, 28, 0, 0, 0.}, 4}, {{2003, 10, 4, 0, 0, 0.}, 8}, {{2003, 10, 5, 0, 0, 0.}, 2}}

correctAnswer = {
  {{{2003, 8, 16, 0, 0, 0.}, 7}, {{2003, 8, 17, 0, 0, 0.}, 3}},
  {{{2003, 8, 23, 0, 0, 0.}, 8}, {{2003, 8, 24, 0, 0, 0.}, 2}},
  {{{2003, 8, 25, 0, 0, 0.}, 1}, {{2003, 8, 26, 0, 0, 0.}, 4}, {{2003, 8, 27, 0, 0, 0.}, 3}},
  {{{2003, 8, 30, 0, 0, 0.}, 8}, {{2003, 8, 31, 0, 0, 0.}, 2}},
  {{{2003, 9, 13, 0, 0, 0.}, 7}, {{2003, 9, 14, 0, 0, 0.}, 2}, {{2003, 9, 15, 0, 0, 0.}, 1}},
  {{{2003, 9, 20, 0, 0, 0.}, 8}, {{2003, 9, 21, 0, 0, 0.}, 2}},
  {{{2003, 9, 26, 0, 0, 0.}, 1}, {{2003, 9, 27, 0, 0, 0.}, 5}, {{2003, 9, 28, 0, 0, 0.}, 4}},
  {{{2003, 10, 4, 0, 0, 0.}, 8}, {{2003, 10, 5, 0, 0, 0.}, 2}}
  }

dayDiff[date1_, date2_] := QuantityMagnitude[DateDifference[date1, date2,"Day"]]

I have tried

GatherBy[list, dayDiff[#1[[1]], #2[[1]]]<=2  && Total[#[[2]] <= 10] &]

to no avail. Thank you.

$\endgroup$
2
$\begingroup$

A possible approach:

split[list_] := Module[{sum = list[[1, 2]]},
    Split[list,
       If[dayDiff[#1[[1]], #2[[1]]] <= 2 && (sum = sum + #2[[2]]) <= 10,
          True,
          sum = #2[[2]];
          False
       ] &
    ]
];

This gives the correct answer:

split[list] == correctAnswer
(* True *)

Update

A rewriting of split to avoid the If statement:

split2[list_] := Module[{sum = list[[1, 2]]}, 
    Split[list,
       (dayDiff[#1[[1]], #2[[1]]] <= 2 && (sum = sum + #2[[2]]) <= 10) ||
       (sum = #2[[2]]; False) &
    ]
];

This yields the same result:

split[list] == split2[list]
(* True *)
$\endgroup$
  • $\begingroup$ This works great. Thank you. I'm not immediately clear on how it works but will figure it out. Thank you again. $\endgroup$ – Ray Troy Sep 30 '16 at 17:54
  • $\begingroup$ @RayTroy Glad this is helpful and thanks for the accept. Split processes its elements two-by-two, so I'm using a local variable to keep track of the sum of all the elements that will form a sublist. At each step of the reading made by Split, a new element enters the play (namely #2). The code takes the value of its second element and add it to the sum (provided dayDiff was satisfied). If the result is smaller than or equal to the bound, this element will join the sublist that is being created by Split, otherwise the sublist will be created and a new one will start with this element. $\endgroup$ – user31159 Sep 30 '16 at 19:50
  • $\begingroup$ @RayTroy In this case, the value of the sum is set to the second element of this element (namely, #2[[2]]), and the reading of Split continues with the following element in the list. $\endgroup$ – user31159 Sep 30 '16 at 19:59

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.