6
$\begingroup$

Tally[list,test] can use a custom function test to judge if elements are equal. But the output will only give the first element in a group. Is there an option to give all the elements? Or how do I write a custom function to do this?

E.g. Given {{1,1},{1,2},{1,2,3},{2,3}}, a tally with test set to head equality would give {{{1,1},3},{{2,3},1}}, but I want something like {{3,{1,1},{1,2},{1,2,3}},{1,{2,3}}}.

$\endgroup$
7
  • 1
    $\begingroup$ Possibly GatherBy is what you need but without more specifics I can't say for sure. $\endgroup$
    – Andy Ross
    Commented Jul 29, 2015 at 4:04
  • $\begingroup$ As Andy says, seems like a union against a Gather is what you're after, but you need to give a more useful description. $\endgroup$
    – ciao
    Commented Jul 29, 2015 at 4:06
  • $\begingroup$ See if Map[{#, Length@#} &, Union /@ Gather[#, <test>]] &@<object> is what you're after, with <test> being the equality test and <object> the target... $\endgroup$
    – ciao
    Commented Jul 29, 2015 at 4:13
  • $\begingroup$ @ciao Why Gather rather than GatherBy? $\endgroup$
    – Mr.Wizard
    Commented Jul 29, 2015 at 4:21
  • 1
    $\begingroup$ @ciao That's a worthy consideration, but I'll also mention that GatherBy is faster when applicable. $\endgroup$
    – Mr.Wizard
    Commented Jul 29, 2015 at 4:26

6 Answers 6

10
$\begingroup$

As has been discussed in the comments you can also use GatherBy.

d = {{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}};
{Length[#], Sequence @@ #} & /@ GatherBy[d, First]

(*{{3, {1, 1}, {1, 2}, {1, 2, 3}}, {1, {2, 3}}}*)
$\endgroup$
4
  • 2
    $\begingroup$ can also be written {Length@{##}, ##} & @@@ GatherBy[d, First] for terse-freaks like me. :^) $\endgroup$
    – Mr.Wizard
    Commented Jul 29, 2015 at 4:46
  • $\begingroup$ @Mr.Wizard I'm one as well but clearly my kung fu is not as strong as yours :) $\endgroup$
    – Andy Ross
    Commented Jul 29, 2015 at 4:51
  • $\begingroup$ lol -- thanks, I think :-) ; since you go for this brand of weirdness: # ~Prepend~ Length@# & /@ d ~GatherBy~ First (or with {Length@#} ~Join~ # ...) $\endgroup$
    – Mr.Wizard
    Commented Jul 29, 2015 at 4:51
  • 1
    $\begingroup$ @Mr.Wizard infix is a lovely obfuscator. If only there were short aliases for built in symbols for the purpose of code golf. Accessed via On["Golf"]. Though <<Golf' is probably better. $\endgroup$
    – Andy Ross
    Commented Jul 29, 2015 at 4:58
6
$\begingroup$
Map[{Length@#, #} &, Union /@ Gather[#, First[#1] === First[#2] &]] &@{{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}}

(* {{3, {{1, 1}, {1, 2}, {1, 2, 3}}}, {1, {{2, 3}}}} *)

Do note, you've reversed the order of tally output in your example (which the above follows): tally puts element first, then count.

If you want all elements including duplications, remove the Union/@... replace the equality test with seasoning of your choice.

$\endgroup$
5
$\begingroup$

Just a Reap/Sow variant.

test = {{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}};
Last@Reap[Sow[{##}, #] & @@@ test, _, {Length@#2, #2} &]
$\endgroup$
2
$\begingroup$
list = {{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}};

Using Query and Splice (new in 12.1)

Query[All, {Length, Splice}] @ GatherBy[list, First]

{{3, {1, 1}, {1, 2}, {1, 2, 3}}, {1, {2, 3}}}

$\endgroup$
1
$\begingroup$

Using the third argument of GroupBy:

list = {{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}};

Values@GroupBy[list, First, {Length@#, If[Length@# == 1, #[[1]], #]} &]

(*{{3, {{1, 1}, {1, 2}, {1, 2, 3}}}, {1, {2, 3}}}*)
$\endgroup$
1
$\begingroup$

There is TallyBy in the WFR. The third argument you can put Identity to get all of them:

ResourceFunction["TallyBy"][{{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}}, First, Identity] // MapApply[Prepend]
{{3,{1,1},{1,2},{1,2,3}},{1,{2,3}}}

Note sure if the count and the items should be on the same level, I have a feeling you might have meant:

ResourceFunction["TallyBy"][{{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}}, First, Identity] // Map[Reverse]
{{3,{{1,1},{1,2},{1,2,3}}},{1,{{2,3}}}}
$\endgroup$
1
  • 1
    $\begingroup$ Please, take a few minutes to write a proper answer. If you don't want to do that, leave that as a comment. Or don't bother at all. $\endgroup$
    – bmf
    Commented Dec 30, 2023 at 11:57

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.