5
$\begingroup$

I have a list in which the first index is mostly increasing, but dips sometimes.

I need to split this list in two or more lists in this way: when the first element of a pair is smaller than the preceding first element, I need to split the list and create new separate lists.

This is an explanatory example:

list = {{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5,50},
        {2, 20}, {3, 30}, {4, 40}, {5, 50}, {1, 10}, {2, 20}, {4, 40}};

newlist1 = {{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}};
newlist2 = {{2, 20} {3, 30} {4, 40} {5, 50}};
newlist3 = {{1, 10}, {2, 20}, {4, 40}};
$\endgroup$
1
  • $\begingroup$ I formatted and rephrased your question and the title slightly to make it more accessible. $\endgroup$
    – Yves Klett
    Commented Jul 31, 2013 at 17:38

2 Answers 2

11
$\begingroup$

It's very easy :

 list = {{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {2, 20}, {3, 
        30}, {4, 40} , {5, 50}, {1, 10}, {2, 20}, {4, 40}};

 Split[list, #1[[1]] < #2[[1]] &] 

{
{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}},
{{2, 20}, {3, 30}, {4,40}, {5, 50}},
{{1, 10}, {2, 20}, {4, 40}}
}

$\endgroup$
6
  • 2
    $\begingroup$ @Mary note Split can be highly abused and can do amazing things, if you can figure out what the splitting function needs to be. Here's everything that references Split on this site. It is worthwhile looking through. $\endgroup$
    – rcollyer
    Commented Jul 31, 2013 at 17:19
  • $\begingroup$ I think this should be <= rather than < based on my reading of the question. $\endgroup$
    – Mr.Wizard
    Commented Jul 31, 2013 at 19:26
  • 1
    $\begingroup$ @rcollyer A better search might be restricted to code. $\endgroup$
    – Mr.Wizard
    Commented Jul 31, 2013 at 21:41
  • $\begingroup$ @Mr.Wizard I did not know you could do that; show off. :) $\endgroup$
    – rcollyer
    Commented Jul 31, 2013 at 22:58
  • $\begingroup$ @andre Thanks very easy solution! $\endgroup$
    – Mary
    Commented Aug 1, 2013 at 6:52
5
$\begingroup$

Here is a function that is several times faster than Split:

runs[a_List] := Inner[a[[# ;; #2]] &, Prepend[# + 1, 1], Append[#, -1], List] & @
  SparseArray[UnitStep @ Differences @ a[[All, 1]], Automatic, 1]["AdjacencyLists"]

Test:

list = {{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}, {2, 20}, {3, 30}, {4, 40},
        {5, 50}, {1, 10}, {2, 20}, {4, 40}};

runs[list] // Column
{{1,10},{2,20},{3,30},{4,40},{5,50}}
{{2,20},{3,30},{4,40},{5,50}}
{{1,10},{2,20},{4,40}}
big = Join @@ ConstantArray[list, 100000];

runs[big]                        // Timing // First
Split[big, #1[[1]] <= #2[[1]] &] // Timing // First

0.234

0.78


Related:
- Conditional Gathering of lists
- Find continuous sequences inside a list

$\endgroup$
3
  • 2
    $\begingroup$ not something for the casual debugger, though :-) $\endgroup$
    – Yves Klett
    Commented Jul 31, 2013 at 19:40
  • $\begingroup$ @Mr.Wizard very smart solution! $\endgroup$
    – Mary
    Commented Aug 1, 2013 at 6:54
  • $\begingroup$ @Mary Thanks; glad you like it. The SparseArray thing is fairly esoteric (and AFAIK undocumented). There are other examples of the use of SparseArray Properties in the second linked post at the bottom of this answer. $\endgroup$
    – Mr.Wizard
    Commented Aug 1, 2013 at 15:22

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.