Shuffle a mapping

We define a map as a set of key-value pairs. For this challenge, you need to take each of the values and assign them to a randomly chosen key.

• You must randomly shuffle the values, and output the resulting map. This means that each time we run your program, we have a chance of getting a different output
• Each possible permutation of the values must have a non-zero chance of appearing.
• All of the original keys and original values must appear in the resulting array. Repeated values must appear the same number of times in the resulting array.

For example, if your map was:

[0:10, 1:10, 5:5]

all of the following must have a chance of appearing:

[0:10, 1:10, 5:5]  (original map)
[0:10, 1:5,  5:10]
[0:10, 1:10, 5:5]  (technically the same map, but I swapped the two tens)
[0:10, 1:5,  5:10]
[0:5,  1:10, 5:10]
[0:5,  1:10, 5:10]

Acceptable input/outputs:

• You can input an array of key-value pairs. You may not input 2 arrays, one with keys, the other with values.
• You can use a string representation of any the above
• If you input an array or a map, you can modify the original object instead of returning
• The input type must match the output type
• If you input an array, the order of the keys must be maintained.
• You can assume that the keys are unique, but you cannot assume that values are unique.

This is a , so answer as short as possible

• Very closely related. (The differences are that in mine the keys are simply the indices of the array, that I require a uniform probability over all permutations and that I disallow built-ins.) Sep 13 '16 at 18:00
• Do the KV pairs have to be in the order [k, v] or would [v, k] be acceptable? Sep 13 '16 at 18:44
• They need to be in [k, v] Sep 13 '16 at 19:03
• Can we input a native map and output an array of key-value pairs? Sep 13 '16 at 21:59
• No, the types need to match. Sep 13 '16 at 22:37

05AB1E, 5 bytes

Input is a list of key-value pairs.

ø       # zip into a list of keys and one of values
`      # flatten
.r    # randomize the values
ø   # zip back again into a list of key-value pairs.

Try it online!

Brachylog, 13 12 bytes

zt@~T,?zh:Tz

Try it online!

Expects a list of 2-element lists as input.

Explanation

z              Zip the input to get a list of keys and a list of values
t@~T,         Take the list of values, and shuffle it ; call that T
?zh      Zip the input to get the list of keys
:Tz   Zip the list of keys with the list of shuffled values

CJam, 9 bytes

{z)mra+z}

Input is a list of key-value pairs.

Test it here.

Explanation

z  e# Zip, to separate keys from values.
)  e# Pull off values.
mr e# Shuffle them.
a+ e# Append them to the array again.
z  e# Zip, to restore key-value pairs.

Alternative solution, same byte count:

{[z~mr]z}
• Pretty sure this is the shortest algorithm in most languages that have Zip :p Sep 13 '16 at 18:06

Jelly, 5 bytes

Ṫ€Ẋṭ"

Try it online!

Explanation

Ṫ€Ẋṭ"  Input: list of [k, v] pairs
Ṫ€     Pop and return the last element of each k-v pair (modifies each list)
Ẋ    Shuffle the list of v's
ṭ"  Append each v back to a k and return
• Looks like TEXt" Sep 13 '16 at 23:32

Python 2, 77 bytes

Uses this option: If you input an array or a map, you can modify the original object instead of returning. Input is a dictionary literal like {0: 10, 1: 10, 5: 5}.

from random import*
D=input()
k=D.keys()
shuffle(k)
D=dict(zip(k,D.values()))

Try it online

Inspiration taken from this SO answer.

Python 3, 107 bytes

Uses Python's native dictionary structure.

Thanks to @mbomb007 for saving a byte.

from random import*
def f(d,o={}):
i=list(d.values());shuffle(i)
for k in d.keys():o[k]=i.pop()
return o

Ideone it!

• Put the import before the function, and use from random import*. Sep 13 '16 at 21:50
• Remove the .keys(). Iterating a dictionary iterates over the keys. Use return dict(zip(d, i)) instead of the for loop. Sep 14 '16 at 12:22

Perl, 35 bytes

Includes +2 for -0p

Give each keys/value separated by space on a STDIN line

shuffle.pl
1 5
3 8
9 2
^D

shuffle.pl:

#!/usr/bin/perl -p0
@F=/ .*/g;s//splice@F,rand@F,1/eg

Mathematica, 32 bytes

{#,RandomSample@#2}&@@(#)&

Input is a list of key-value pairs. is Mathematica's transposition operator, and RandomSample can be used to shuffle a list.

php, 84 bytes

<?= serialise(array_combine(array_keys($a=unserialize($argv)),shuffle($a)?$a:0));

Takes input as a serialised array, outputs the same.

Clojure, 40 34 bytes

#(zipmap(keys %)(shuffle(vals %)))

Takes the keys and values from m (a map), shuffles the values and zips them up into a map.

• Use the function macro: #(zipmap(keys %)(shuffle(vals %))) Sep 13 '16 at 21:48

PowerShell v2+, 52 bytes

param($a)$a|%{$_}|sort {random}|%{$a[$i++],$_}

Takes input as an array of tuples, which is significantly shorter than using a hash (which would require .GetEnumerator() and whatnot to work).

We loop the input array |%{...}, each iteration pulling out the second element $_. Those are piped into Sort-Object with the {Get-Random} as the sorting key. This will assign a random weight from 0 to [Int32]::MaxValue to each element for sorting. Those are piped into another loop |%{...}, with each iteration outputting a tuple of the corresponding first element of the tuple and the sorted number. Examples The examples here have an additional -join',' on the tuple output so it's shown better on the console, as the default output for multi-dimensional arrays is hard to read. PS C:\Tools\Scripts\golfing> .\shuffle-a-mapping.ps1 ((0,10),(1,10),(5,5)) 0,10 1,5 5,10 PS C:\Tools\Scripts\golfing> .\shuffle-a-mapping.ps1 ((0,10),(1,10),(5,5)) 0,10 1,10 5,5 PS C:\Tools\Scripts\golfing> .\shuffle-a-mapping.ps1 ((1,1),(2,2),(3,3),(4,4),(5,5)) 1,2 2,4 3,3 4,5 5,1 This works for non-integer values as well with no modifications. PS C:\Tools\Scripts\golfing> .\shuffle-a-mapping.ps1 (('one','one'),('two','two'),('three','three'),('four','four')) one,four two,three three,two four,one JavaScript (ES6), 89 bytes a=>a.map((_,i)=>[i,Math.random()]).sort((a,b)=>a-b).map(([i],j)=>[a[j],a[i]]) Perl 6, 28 bytes {%(.keys.pick(*)Z=>.values)} Input is a Hash ( Technically any value with a .keys method and a .values method would work, but the output is a Hash ) Explanation: # bare block lambda with implicit parameter ｢$_｣
{

# turn the list of key => value Pairs into a Hash
%(
# get the keys from ｢$_｣ ( implicit method call on ｢$_｣ )
.keys

# get all of the keys in random order
.pick(*)

# zip using ｢&infix:« => »｣ the Pair constructor
Z[=>]

# the values from ｢$_｣ ( implicit method call on ｢$_｣ )
.values
)
}

A variant that would work for the other built in Hash like object types is:

{.WHAT.(.keys.pick(*)Z=>.values)}

.WHAT on an object returns the type.

R, 47 (28) bytes

A bit late to the party but though I'd post a solution in R using builtins.

The closest thing R has to an array with key/value mapping is a list. The following function takes a list object as input and outputs a list with its values shuffled.

function(x)return(setNames(sample(x),names(x)))

Explained

The builtin setNames() can assign names to objects by inputting a R-vector of names. Hence, first shuffle the list by sample() which shuffles the pairs, and then assign the names in the original order using names().

Example:

z  <- list(fish = 1, dog = 2, cat = 3, monkey = 4, harambe = 69)

f=function(x)return(setNames(sample(x),names(x)))
f(z)

$fish  3$dog
 1

$cat  2$monkey
 69

\$harambe
 4

If x is assumed to be defined there's no need for function wrapping and the program reduces to 28 bytes.

setNames(sample(x),names(x))

Java 7, 156 bytes

import java.util.*;void c(Map m){List t=new ArrayList(m.values());Collections.shuffle(t);Iterator i=t.iterator();for(Object k:m.keySet())m.put(k,i.next());}

Ungolfed:

void c(Map m){
List t = new ArrayList(m.values());
Collections.shuffle(t);
Iterator i = t.iterator();
for(Object k : m.keySet()){
m.put(k, i.next());
}
}

Test code:

Try it here.

import java.util.*;
class M{
static void c(Map m){List t=new ArrayList(m.values());Collections.shuffle(t);Iterator i=t.iterator();for(Object k:m.keySet())m.put(k,i.next());}

public static void main(String[]a){
for(int i=0;i<10;i++){
Map m=new HashMap();
m.put(0, 10);
m.put(1, 10);
m.put(5, 5);
c(m);
System.out.println(m);
}
}
}

Possible output:

{0=5, 1=10, 5=10}
{0=10, 1=10, 5=5}
{0=10, 1=5, 5=10}
{0=10, 1=10, 5=5}
{0=10, 1=10, 5=5}
{0=10, 1=10, 5=5}
{0=10, 1=10, 5=5}
{0=10, 1=10, 5=5}
{0=10, 1=5, 5=10}
{0=5, 1=10, 5=10}