How do I split a list of numbers to monotonic sequences?
Starting at 10.1, there's a fairly neat solution using SequenceCases
:
list = {1, 2, 4, 5, 7, 11, 8, 7, 3, 1, -3, -2, 6, 7, 80};
SequenceCases[list, x_ /; Less @@ x || Greater @@ x]
(* {{1, 2, 4, 5, 7, 11}, {8, 7, 3, 1, -3}, {-2, 6, 7, 80}} *)
This works because SequenceCases
defaults to Overlaps -> False
, such that e.g. 11
won't appear in two of the sublists.
Of course, if you want to allow repeated elements (i.e. not strictly monotonic sequences), use LessEqual
and GreaterEqual
respectively.
For a pre-10.1 solution using Split
see Xavier's answer.
Martin provided a nice answer with SequenceCases
. For Mathematica versions prior to 10.1, depending on what OP wants for lists of the form:
list2 = {1, 2, 4, 5, 7, 11, 8, 9, 10, 12, -3, -2, 6, 7, 80};
namely, for lists that have consecutive sequences of same monotonicity, an approach could be:
splitMon[list_] :=
Split[list,
sign =.;
If[sign (#2 - #1) > 0, True, sign =.; False, sign = Sign[#2 - #1]; True] &
];
Examples:
SequenceCases[list, x_ /; Less @@ x || Greater @@ x]
% === splitMon[list]
(* {{1, 2, 4, 5, 7, 11}, {8, 7, 3, 1, -3}, {-2, 6, 7, 80}} *)
(* True *)
SequenceCases[list2, x_ /; Less @@ x || Greater @@ x]
% === splitMon[list2]
(* {{1, 2, 4, 5, 7, 11}, {8, 9, 10, 12}, {-3, -2, 6, 7, 80}} *)
(* True *)
Here's a solution using SplitBy
. It works also for elements that are repeated no more than once, but it can be fixed if there are elements repeated more than once.
monotonicSplit[list_] := SplitBy[Transpose[{#, {#1, ##} & @@ Sign@Differences@#}] &@list, Last][[All, All, 1]]
list = {1, 2, 4, 5, 6, 6, 7, 3, 1, -3, -2, 6, 7, 80};
monotonicSplit[list]
(* {{1, 2, 4, 5, 6}, {6}, {7}, {3, 1, -3}, {-2, 6, 7, 80}} *)