Algorithm for matching HashMap key with another random HashMap key, never duplicating values or matching itself

谁都会走 提交于 2019-12-11 22:42:36

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!