# Fast functional method for multiplying duplication numbers in a large list

Consider a list of symbols:

mySet = {a, b, b, c, a, b, c, d};


I would like to form the product of duplication numbers. In the example above, I have 2 a's, 3 b's, 2 c's and 1 d. So the result I need is $2\times3\times2\times1 = 12$.

Here is what I came up with. I use Tally to count up the duplication numbers, and then multiply all the numbers which are in the second part.

duplProd[stuff_List] := Times @@ Transpose[Tally[stuff]][[2]]


And I get the expected.

duplProd[mySet]
(* 12 *)


But I have enormous lists (like with 1000 to 10000 entries). Is there a way to achieve this result that runs faster? I know that I must avoid Part since it makes things go slowly.

Version 10:

Times @@ Counts @ mySet
(* 12 *)


Other versions:

Times @@ Length /@ Gather @ mySet
(* 12 *)

Times @@ Length /@ Split @ Sort @ mySet
(* 12 *)


Some timings:

testdata=RandomChoice[CharacterRange["a","z"],{10000}];
Times @@ Transpose[Tally[testdata]][[2]]//AbsoluteTiming//First
(*  0.00170  *)
Times@@Counts@testdata//AbsoluteTiming//First
(*  0.00171  *)
Times@@Length/@Gather@testdata//AbsoluteTiming//First
(*  0.00078  *)
Times@@Length/@Split@Sort@testdata//AbsoluteTiming//First
(*  0.00187  *)
Times @@ Last /@ Tally@testdata//AbsoluteTiming//First
(*  0.00170  *)
Times @@ Tally@testdata // Last//AbsoluteTiming//First
(*  0.00170  *)


These are marginally faster than yours:

mySet = RandomChoice[CharacterRange["a", "z"], 10000];

Times @@ Last /@ Tally@mySet


or:

Times @@ Tally@mySet // Last