8
$\begingroup$

I have some list which looks like

{{0,1},{4},{0,0,1},{2,0,1},{3,0,0},{3,1},{0,0,0,4}}

and I need to group lists with equal sum of elements in ascending order like

{{{0,1},{0,0,1}},{{2,0,1},{3,0,0}},{{4},{3,1},{0,0,0,4}}}

and for

{{0, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {1, 1, 1, 1, 0}, {1, 1, 0, 1, 1}, {0, 1, 1, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}

I expected to see

{{{0, 0, 0, 0, 0}}, {{1, 1, 0, 0, 0}, {0, 1, 1, 0, 0}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}, {{1, 1, 1, 1, 0}, {1, 1, 0, 1, 1}, {0, 1, 1, 1, 1}}}
$\endgroup$
11
$\begingroup$
Sort@GatherBy[{{0, 1}, {4}, {0, 0, 1}, {2, 0, 1}, {3, 0, 0}, {3, 1}, {0, 0, 0, 4}}, Total]

To make sure Sort always gets it right:

Sort[GatherBy[n, Total], Less[Total@First[#], Total@First[#2]] &]
$\endgroup$
  • $\begingroup$ n = {{0, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {1, 1, 1, 1, 0}, {1, 1, 0, 1, 1}, {0, 1, 1, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}; Sort@GatherBy[n, Total]; gives {{{0, 0, 0, 0, 0}}, {{1, 1, 1, 1, 0}, {1, 1, 0, 1, 1}, {0, 1, 1, 1, 1}}, {{1, 1, 0, 0, 0}, {0, 1, 1, 0, 0}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}} but I would like to get {{{0, 0, 0, 0, 0}}, {{1, 1, 0, 0, 0}, {0, 1, 1, 0, 0}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}, {{1, 1, 1, 1, 0}, {1, 1, 0, 1, 1}, {0, 1, 1, 1, 1}}} $\endgroup$ – Филипп Цветков Oct 16 '13 at 13:53
  • $\begingroup$ Yes, it was only plain luck that the first version worked without having to use SortBy. But that's exactly why I added another version which, as I said, "always gets it right." (In the first version it works because the first number in each sublist is ascending in the way you would like to have it sorted. $\endgroup$ – C. E. Oct 16 '13 at 15:10
  • $\begingroup$ So just to be clear, the topmost solution is only valid for the first example you provided. Not for subsequent examples. But I foresaw this, and provided the first version only as a curiosity to show that in this particular case it's this simple. $\endgroup$ – C. E. Oct 16 '13 at 15:12
  • $\begingroup$ Your second line appears to be a SortBy[...,True]. This just defaults down to Sort again and makes it equal to your first solution. $\endgroup$ – jVincent Oct 16 '13 at 15:43
  • $\begingroup$ @jVincent Yeah, silly me. I corrected it. I sure would have appreciated some downvotes/comments to alert me! With seven upvotes you tend to think you have it right! Ty! (+1 for yours, I like it better. It should get at least 14 upvotes.) $\endgroup$ – C. E. Oct 16 '13 at 15:48
7
$\begingroup$

A simple approach is to just use:

GatherBy[SortBy[list,Total],Total]

This ensures that they appear in the correct order since they are gathered based on the appearance of the first element. In each sublist with the same total, they will be ordered based on OrderedQ, which puts them in order of number of elements afaik.

To verify that it works out:

 listA={{0,1},{4},{0,0,1},{2,0,1},{3,0,0},{3,1},{0,0,0,4}};
 listB={{0, 0, 0, 0, 0, 1}, {4}, {0, 0, 0, 0, 1}, {2, 0, 1}, {3, 0, 0}, {3, 1}, {0, 0, 0, 4}};

verify[v_] := Total[First[#]] & /@ v
verify@GatherBy[SortBy[listA, Total], Total]
verify@GatherBy[SortBy[listB, Total], Total]
(* {1,3,4} *)
(* {1,3,4} *)
$\endgroup$
5
$\begingroup$

I would write it like this:

list ~SortBy~ {Total} ~SplitBy~ Total

Note that putting the SortBy function inside a list (i.e. {Total} instead of just Total) means that SortBy will give a stable sort, so elements with the same total will stay in the order they were in the original list.

$\endgroup$
  • $\begingroup$ neat idea! Thanks for sharing/explaining $\endgroup$ – Pinguin Dirk Oct 16 '13 at 16:33
3
$\begingroup$

Just for fun:

Pick[list, Total /@ list, #] & /@ Union[Total /@ list]

=> {{{0, 1}, {0, 0, 1}}, {{2, 0, 1}, {3, 0, 0}}, {{4}, {3, 1}, {0, 0, 0, 4}}}

where

list = {{0, 1}, {4}, {0, 0, 1}, {2, 0, 1}, {3, 0, 0}, {3, 1}, {0, 0, 
   0, 4}}

And

Pick[n, Total /@ n, #] & /@ 
  Union[Total /@ n] == {{{0, 0, 0, 0, 0}}, {{1, 1, 0, 0, 0}, {0, 1, 1,
     0, 0}, {0, 0, 1, 1, 0}, {0, 0, 0, 1, 1}}, {{1, 1, 1, 1, 0}, {1, 
    1, 0, 1, 1}, {0, 1, 1, 1, 1}}}

=> True

$\endgroup$
1
$\begingroup$
lst = {{0, 1}, {4}, {0, 0, 1}, {2, 0, 1}, {3, 0, 0}, {3, 1}, {0, 0, 0, 4}};

Values @ SortBy[Total @ First @ # &] @ GroupBy[Total] @ lst

{{{0, 1}, {0, 0, 1}}, {{2, 0, 1}, {3, 0, 0}}, {{4}, {3, 1}, {0, 0, 0, 4}}}

$\endgroup$
1
$\begingroup$
lst[[#]] & /@ Values[KeySort[PositionIndex[Total[lst, {2}]]]]

{{{0, 1}, {0, 0, 1}}, {{2, 0, 1}, {3, 0, 0}}, {{4}, {3, 1}, {0, 0, 0, 4}}}

Since 11.2 also

With[{sums = Total[lst, {2}]},
 TakeList[lst[[Ordering[sums]]], Values[KeySort[Counts[sums]]]]]
$\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.