# What's the cleanest functional-programming style way to perform this list operation?

I am looking for the correct method for accomplishing the unknown piece in the following code snippet:

rolls = Tuples[Range[1, 4], {2}]

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

Tally[rolls, Min[#1] == Min[#2] &]

{{{1, 1}, 7}, {{2, 2}, 5}, {{3, 3}, 3}, {{4, 4}, 1}}

(*Unknown List Manipulation Code*)

(1*7 + 2*5 + 3*3 + 4*1)/Length[rolls]
(*where previous result is of the form {{{a, b}, c}, ...}
the numerator is the sum of Min[a,b]*c for every item in the list that is the previous result*)


I can imagine some very complex solutions, but I suspect that there is an elegant functional solution that I am missing.

rolls = Tuples[Range[1, 4], {2}];
tally = Tally[rolls, Min[#1] == Min[#2] &];
lis = {{{1, 1}, 7}, {{2, 2}, 5}, {{3, 3}, 3}, {{4, 4}, 1}}
Total[Min@#[[1]]*#[[2]] & /@ lis]/Length[rolls]


Which gives:

15/8

• All of these answers are useful, but this one best matches what I was looking for. Commented Sep 20, 2013 at 2:31

Is this what you want?

Min /@ Tuples[Range[1, 4], {2}] // Mean

15/8


Pinguin Dirk forced me to post this:

f[n_, k_] := Range[n, k].Reverse@Range[1, 2 (k - n + 1), 2]/(k - n + 1)^2


it appears to be 10 times faster than:

Plus @@ Times @@@ Transpose@{##, Range[2 Length[#] - 1, 1, -2]
}/Length[#]^2 &@Range[50, 10000] // AbsoluteTiming

{0.010001, 100500125/29853}

f[50, 10000] // AbsoluteTiming

{0.001000, 100500125/29853}

• @Kuba: forced you? :) But I like the implementation! I was just inspired by other Q&As where people discuss how to avoid Tuples and its friends (and this was an easy one). Nice work Commented Sep 20, 2013 at 11:14
• @PinguinDirk I totally agree, but you know: "let's test Kuba's solution... 1000 times slower". I had to respond :p
– Kuba
Commented Sep 20, 2013 at 11:39
• @Kuba: I took yours cause I like it best! But a good challenge is always welcome, more will come! Commented Sep 20, 2013 at 11:40
• @PinguinDirk Indeed, it's the motor of the progress. :) and hank you, I'm glad you like it.
– Kuba
Commented Sep 20, 2013 at 11:42

If it should be functional programming style, try this:

Plus @@ (Min @ #1  #2& @@@ {
{{1, 1}, 7}, {{2, 2}, 5}, {{3, 3}, 3}, {{4, 4}, 1}})/Length[rolls]

15/8


You want the sum of Min[a, b] c for every {{a, b}, c} in the list? You can quite literally do that.

rolls = Tuples[Range[1, 4], {2}];
tally = Tally[rolls, Min[#1] == Min[#2] &];
numerator = Total[tally /. {{a_, b_}, c_} :> Min[a, b] c]
result = numerator/Length[rolls]

• What does the :> operator do? Could you link me to the documentation page? Commented Sep 20, 2013 at 2:08
• @Techrocket9 it's called RuleDelayed, you can just type :> in mathematica and hit F1 to get the documentation
– ssch
Commented Sep 20, 2013 at 2:08

I am assuming a sorted list as input - else Sort it first

Looking at the problem you want to solve, I suggest not to use Tuples, as this will get slow, the more rolls you have. So here's a way to solve it without Tuples, but rather basic combinatorics:

 Plus @@ Times @@@ Transpose@{##, Range[2 Length[#] - 1, 1, -2]}/Length[#]^2 &@Range[4]


15/8

To compare speed, I chose the nice solution of @Kuba, using Range[5,10000] (explicitly another starting point, to see if solutions agree) (note: Range[5,10000,2] etc also works)

Plus @@ Times @@@ Transpose@{##, Range[2 Length[#] - 1, 1, -2]}/
Length[#]^2 &@Range[50, 10000] // AbsoluteTiming


{0.006532, 100500125/29853}

Min /@ Tuples[Range[50, 10000], {2}] // Mean // AbsoluteTiming


{6.524025, 100500125/29853}

• Ok, I've posted something faster than Tuples :)
– Kuba
Commented Sep 20, 2013 at 7:39
• you win :) @Kuba Commented Sep 20, 2013 at 10:08
• I think the case is still open :) Thanks for the kick.
– Kuba
Commented Sep 20, 2013 at 10:12

Here's a solution using GroupBy[]:

Total[KeyValueMap[Times, GroupBy[rolls, Min, Length]]]/Length[rolls]
15/8