1
$\begingroup$

I have a nested list below.

{{{0.,0.,1.},1.},{{0.,0.1,0.9},1.},{{0.,0.2,0.8},1.},{{0.,0.3,0.7},1.},{{0.,0.4,0.6},1.},{{0.,0.5,0.5},1.},{{0.,0.6,0.4},1.},{{0.,0.7,0.3},1.},{{0.,0.8,0.2},1.},{{0.,0.9,0.1},1.},{{0.,1.,0.},1.},{{0.1,0.,0.9},68.6},{{0.1,0.1,0.8},68.6},{{0.1,0.2,0.7},68.6},{{0.1,0.3,0.6},68.6},{{0.1,0.4,0.5},68.6},{{0.1,0.5,0.4},68.6},{{0.1,0.6,0.3},68.6},{{0.1,0.7,0.2},68.6},{{0.1,0.8,0.1},68.6},{{0.1,0.9,0.},68.6},{{0.2,0.,0.8},136.2},{{0.2,0.1,0.7},136.2},{{0.2,0.2,0.6},136.2},{{0.2,0.3,0.5},136.2},{{0.2,0.4,0.4},136.2},{{0.2,0.5,0.3},136.2},{{0.2,0.6,0.2},136.2},{{0.2,0.7,0.1},136.2},{{0.2,0.8,0.},136.2},{{0.3,0.,0.7},203.8},{{0.3,0.1,0.6},203.8},{{0.3,0.2,0.5},203.8},{{0.3,0.3,0.4},203.8},{{0.3,0.4,0.3},203.8},{{0.3,0.5,0.2},203.8},{{0.3,0.6,0.1},203.8},{{0.3,0.7,0.},203.8},{{0.4,0.,0.6},271.4},{{0.4,0.1,0.5},271.4},{{0.4,0.2,0.4},271.4},{{0.4,0.3,0.3},271.4},{{0.4,0.4,0.2},271.4},{{0.4,0.5,0.1},271.4},{{0.4,0.6,0.},271.4},{{0.5,0.,0.5},339.},{{0.5,0.1,0.4},339.},{{0.5,0.2,0.3},339.},{{0.5,0.3,0.2},339.},{{0.5,0.4,0.1},339.},{{0.5,0.5,0.},339.},{{0.6,0.,0.4},406.6},{{0.6,0.1,0.3},406.6},{{0.6,0.2,0.2},406.6},{{0.6,0.3,0.1},406.6},{{0.6,0.4,0.},406.6},{{0.7,0.,0.3},474.2},{{0.7,0.1,0.2},474.2},{{0.7,0.2,0.1},474.2},{{0.7,0.3,0.},474.2},{{0.8,0.,0.2},541.8},{{0.8,0.1,0.1},541.8},{{0.8,0.2,0.},541.8},{{0.9,0.,0.1},609.4},{{0.9,0.1,0.},609.4},{{1.,0.,0.},677.}}

I want to split it into several lists if the second elements are same like below.

{{{0., 0., 1.}, 1.}, {{0., 0.1, 0.9}, 1.}, {{0., 0.2, 0.8},1.}, {{0., 0.3, 0.7}, 1.}, {{0., 0.4, 0.6}, 1.}, {{0., 0.5, 0.5},1.}, {{0., 0.6, 0.4}, 1.}, {{0., 0.7, 0.3}, 1.}, {{0., 0.8, 0.2},1.}, {{0., 0.9, 0.1}, 1.}, {{0., 1., 0.}, 1.}}


{{{0.1, 0., 0.9}, 68.6}, {{0.1, 0.1, 0.8}, 68.6}, {{0.1, 0.2, 0.7},68.6},{{0.1, 0.3, 0.6}, 68.6}, {{0.1, 0.4, 0.5},68.6},{{0.1, 0.5, 0.4}, 68.6},{{0.1, 0.6, 0.3},68.6}, {{0.1, 0.7, 0.2}, 68.6}, {{0.1, 0.8, 0.1},68.6},{{0.1, 0.9, 0.}, 68.6}}



{{{0.9, 0., 0.1}, 609.4}, {{0.9, 0.1, 0.}, 609.4}}

{{{1., 0., 0.}, 677.}}

I have tried Cases, Split, Part without success. Your help is greatly appreciated.

Thank you in advance.

$\endgroup$
3
  • 8
    $\begingroup$ SplitBy[data, Last] $\endgroup$
    – corey979
    Commented Nov 7, 2018 at 13:53
  • $\begingroup$ Thank you. SplitBy grouped the list. I was wondering using the pattern matching so that it can be used for any position of the list in stead of Last. $\endgroup$
    – yaykhel
    Commented Nov 7, 2018 at 14:20
  • 2
    $\begingroup$ This gives the same result: SplitBy[data, #[[-1]] &], and you can change the Part specification to suit your needs. $\endgroup$
    – corey979
    Commented Nov 7, 2018 at 14:38

3 Answers 3

0
$\begingroup$

You may use GatherBy and Replace for your matching by pattern requirement.

For the simpler cases you may be able to find a function like Last or create your own with Function and Part. The below are equivalent.

GatherBy[list, Last]
GatherBy[list, #[[-1]]&]

For the pattern match requirement you may use Replace. For the simple case of Last then;

GatherBy[list, Replace[{_List, n_} :> n]]

Or for parts {1, 1} and {2}

GatherBy[list, Replace[{{n1_, ___}, n2_} :> {n1, n2}]]

and so on.

Hope this helps.

$\endgroup$
2
$\begingroup$

Based on my intervals from Find subsequences of consecutive integers inside a list:

mySplit[a_List, pos___] :=
  Take[a, #] & /@ ({Prepend[# + 1, 1], Append[#, -1]}\[Transpose]) &@
    SparseArray[ Differences @ a[[All, pos]] ]["AdjacencyLists"]

This is faster than SplitBy:

dat = (* your expression *)

SplitBy[dat, #[[2]] &] === mySplit[dat, 2]

big = Join @@ Table[dat, {50}];
SplitBy[big, #[[2]] &] // RepeatedTiming // First
mySplit[big, 2]        // RepeatedTiming // First
True

0.00514

0.000579
$\endgroup$
0
$\begingroup$

Using TakeList in combination with Differences and SparseArray:

ClearAll[splitBy]
splitBy = TakeList[#, Differences @ Join[{0}, 
    SparseArray[Differences @ #[[All, #2]]]["AdjacencyLists"] , {Length @ #}]] &; 

This is twice as fast as Mr.Wizard's mySplit:

big = Join @@ Table[dat, {50}];
r1 = SplitBy[big, #[[2]] &]; // RepeatedTiming // First

0.00572

r2 = mySplit[big, 2]; // RepeatedTiming  // First

0.000778

r3 = splitBy[big, 2]; // RepeatedTiming  // First 

0.000315

r1 == r2 == r3

True

Also,

splitBy2 = TakeList[#, Length /@ Split[#[[All, #2]]]]&
r4 = splitBy2[big, 2]; // RepeatedTiming  // First 

0.000452

r1 == r4

True

$\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.