5
$\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$
  • 1
    $\begingroup$ Possibly GatherBy is what you need but without more specifics I can't say for sure. $\endgroup$ – Andy Ross Jul 29 '15 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 Jul 29 '15 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 Jul 29 '15 at 4:13
  • $\begingroup$ @ciao Why Gather rather than GatherBy? $\endgroup$ – Mr.Wizard Jul 29 '15 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 Jul 29 '15 at 4:26
9
$\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$
  • 2
    $\begingroup$ can also be written {Length@{##}, ##} & @@@ GatherBy[d, First] for terse-freaks like me. :^) $\endgroup$ – Mr.Wizard Jul 29 '15 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 Jul 29 '15 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 Jul 29 '15 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 Jul 29 '15 at 4:58
5
$\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$
3
$\begingroup$

Just a Reap/Sow variant.

test = {{1, 1}, {1, 2}, {1, 2, 3}, {2, 3}};
Last@Reap[Sow[{##}, #] & @@@ test, _, {Length@#2, #2} &]
$\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.