4
$\begingroup$

I have 4 different items {1, 2, 3, 4}. I want to obtain all possible pairs of two of the items. I have written:

n = 4;
x1 = Tuples[Range@n, n];

Cases[x1, {a_, a_, b_, b_} /; a != b]

gives the desired result:

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

Now I choose

n = 6;
x2 = Tuples[Range@n, n];

Cases[x2, {a_, a_, b_, b_, c_, c_} /; a != b && a != c && b != c];
% // Short

{{1,1,2,2,3,3},{1,1,2,2,4,4},<<116>>,{6,6,5,5,3,3},{6,6,5,5,4,4}}

again gives the desired result.

How would you automate this (for even n)?

Are there better alternatives?

$\endgroup$
  • $\begingroup$ @Szabolcs Well almost, but not quite. For Subsets you'll need to generate additional permutations in order to get the desired output, and for Tuples you'll need to throw away cases of repeated pairs. $\endgroup$ – Teake Nutma Jul 16 '14 at 17:49
  • $\begingroup$ @Öska Thanks for the edit and Short $\endgroup$ – eldo Jul 16 '14 at 19:47
4
$\begingroup$

This is another approach:

pairRiffle[n_?EvenQ] := Riffle[#, #] & /@ (Permutations[Range@n, {n/2}])

pairRiffle[4]
(* {{1, 1, 2, 2}, {1, 1, 3, 3}, {1, 1, 4, 4}, {2, 2, 1, 1}, {2, 2, 3, 
  3}, {2, 2, 4, 4}, {3, 3, 1, 1}, {3, 3, 2, 2}, {3, 3, 4, 4}, {4, 4, 
  1, 1}, {4, 4, 2, 2}, {4, 4, 3, 3}} *)

Edit: in fact I could do without the Riffle and just use the transformation rule in @Teake Nutma's answer

pairHybrid[n_?EvenQ] :=  Permutations[Range@n, {n/2}] /. x_Integer -> Sequence[x, x]

pairHybrid[10] == Sort@AllPairs[10]
(* True *)
pairRiffle[10] == Sort@AllPairs[10]
(* True *)
$\endgroup$
  • 1
    $\begingroup$ +1 for the second argument of Permutations. $\endgroup$ – Teake Nutma Jul 16 '14 at 19:14
  • $\begingroup$ Thanks! +1 to you too for the inspiration. $\endgroup$ – seismatica Jul 16 '14 at 19:16
  • $\begingroup$ @seismatica +1 A funny development :) $\endgroup$ – eldo Jul 16 '14 at 19:18
  • $\begingroup$ Nice use of Riffle! That's my favorite way to double elements. $\endgroup$ – Mr.Wizard Jul 22 '14 at 2:54
6
$\begingroup$

This should do the job:

AllPairs[n_?EvenQ] := 
   Flatten[Permutations /@ Subsets[Range[n], {n/2}], 1] /. x_Integer :> Sequence[x, x]

AllPairs[4]
{
  {1, 1, 2, 2}, {2, 2, 1, 1}, {1, 1, 3, 3}, {3, 3, 1, 1}, 
  {1, 1, 4, 4}, {4, 4, 1, 1}, {2, 2, 3, 3}, {3, 3, 2, 2}, 
  {2, 2, 4, 4}, {4, 4, 2, 2}, {3, 3, 4, 4}, {4, 4, 3, 3}
}
$\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.