3
$\begingroup$

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.

$\endgroup$
2
$\begingroup$

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  *)
$\endgroup$
2
$\begingroup$

These are marginally faster than yours:

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

Times @@ Last /@ Tally@mySet

or:

Times @@ Tally@mySet // Last
$\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.