问题
It's possible this is not most logical/easyiest/effective way of doing this. I would love some input on a better logic, so I'll rather try to explain the problem.
List:
Jon - null
Dad - null
Mom - null
Thor - null
July - null
I want to create a method that matches these with another 'key' at random, not having duplicate values or having a key and value which are the same.
Another problem is if there are for example 3 keys.
1 - null
2 - null
3 - null
Iteration 1:
1 - 2
2 - null
3 - null
Iteration 2:
1 - 2
2 - 1
3 - null
Iteration 3:
???
It's possible a HashMap not is the most logical way of storing this.
回答1:
What you are talking about is called a derangement. As far as I know it's quite difficult to generate derangements in such a way that they are all equally likely, but there is a reasonably effective way of generating them.
Simply iterate over the keys and assign a value at random from the set of keys that haven't already been used, always avoiding the current key.
You can actually only get stuck at the very last step. E.g. something like this
1 - 2
2 - 4
3 - 1
4 - 3
5 - ???
If this happens, just choose one of the values already selected, and swap.
1 - 2
2 - 5 <-- swap
3 - 1
4 - 3
5 - 4 <-- swap
An implementation of Set with an efficient method for getting random elements is given here.
回答2:
The answer isn't in java, but since this is more of an algorithms question, I'm sure you could figure out how to translate the python to java:
import random
# The original collection, using a set instead of map/hash since we don't care
# about the values
set1 = set(range(100))
# Make a copy of set1, we're using a list here so that random.choice will work
set2 = list(set1)
pairs = []
for i in set1:
# Deal with the final item being the same in both collections,
# swap with the first one
if len(set2) == 1 and i == set2[0]:
tmp = pairs[0][1]
pairs[0][1] = set2[0]
pairs.append([i,tmp])
break
# Pick random items from set2 until you get one that isn't the same as i
while True:
j = random.choice(set2)
if i != j:
break
# Remove the value from set2 so we won't pick it again
# In this example, set2 is actually a list so that random.choice would work on it
# This could be kind of expensive, might be better using an actual set
set2.remove(j)
# Add our pair to the paired up list
pairs.append([i,j])
回答3:
Copy your list into a queue, shuffle it, then assign pairs from list and queue. If the element in the queue is the same, put it back at the tail and take the next one.
List<String> list = <list with your items>;
ArrayDeque<String> queue = new ArrayDeque<>(list1);
Collections.shuffle(queue);
List<StringPair> result = new ArrayList<>();
for (String s : list) {
for (String s2; (s2 = queue.poll()).equals(s);)
queue.offer(s2);
result.add(s, s2);
}
The above is a basic outline and probably needs some more work, but it seems like a good approach.
来源:https://stackoverflow.com/questions/33682455/algorithm-for-matching-hashmap-key-with-another-random-hashmap-key-never-duplic