如果有两个以上的数组项,我需要找到一种快速有效的方法来创建唯一对。
我的第一个问题是我提出的这个代码有时会抛出 java.lang.StackOverflowError ,为什么?我知道它会在帮助器中进行递归调用,但是如何修复呢?
我的第二个问题是如何提高代码效率。我不需要使用数组 - 它可能是其他一些集合类型。
这就是我的想法:
import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;
/**
* Generates unique pairs from items in array. Each item cannot occur more than
* once as key nor value.
*
* @author lkallas
*/
public class UniquePairs {
private static final String[] NAMES
= new String[]{"Aaron", "Barney", "Charlie", "Desiré", "Edward"};
private static final HashMap<String, String> PAIRS = new HashMap<>();
public static void main(String[] args) {
// Check if there is more than one item in array.
if (NAMES.length > 1) {
// Find pairs
for (String name : NAMES) {
if (!PAIRS.containsKey(name)) {
PAIRS.put(name, helper(name));
}
}
// Show results.
PAIRS.entrySet().stream().forEach((pair) -> {
System.out.println(pair.getKey() + " - " + pair.getValue());
});
} else {
System.out.println(NAMES[0]);
}
}
/**
* Helper for finding partner.
*
* @param key Name that need partner.
* @return Unique partner.
*/
private static String helper(String key) {
// Get random partner from array.
String partner = NAMES[getRandomInt(0, NAMES.length - 1)];
// Cannot pair up a name with itself. Also partner cannot occur more than once.
if (key.equals(partner) || PAIRS.containsValue(partner)) {
partner = helper(key);
}
return partner;
}
/**
* Random integer in the given range.
*
* @param min Minimum value of the random integer.
* @param max Maximum value of the random integer.
* @return Random integer in given range.
*/
private static int getRandomInt(int min, int max) {
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
}
修改 使用
return ThreadLocalRandom.current().nextInt(min, max + 1);
而不是
return new Random().nextInt((max - min) + 1) + min;
编辑2:
为此类操作创建了特殊类。如有必要,请随意使用。
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
*
* @author lkallas
*/
public class MatchMaker {
private final Map<Object, Object> PAIRS;
private List<? extends Object> items;
public MatchMaker() {
this.PAIRS = new HashMap<>();
}
/**
* Pairs items uniquely and randomly so that keys nor values are repeated.
* For proper pairing of Objects it is recommended to provide your own
* implementation of <code>equals()</code> method. Also bear in mind that
* you should also override <code>hashCode()</code> if there's any chance of
* your objects being used in a hash table.
*
* @param input List with objects that are paired with each other.
* @return Map with generated pairs.
* @throws IllegalArgumentException When input List is empty or contains
* only one item.
*/
public Map<?, ?> getPairs(List<? extends Object> input)
throws IllegalArgumentException {
if (input.size() > 1) {
items = input;
for (int i = 0; i < input.size() - 1; i++) {
Object k = input.get(i);
PAIRS.put(k, getPartner(k));
}
Object k = items.get(items.size() - 1);
if (PAIRS.containsValue(k)) {
PAIRS.put(k, getPartner(k));
} else {
Object k1 = items.get(getRandomInt(0, items.size() - 1));
PAIRS.put(k, PAIRS.get(k1));
PAIRS.put(k1, k);
}
} else {
throw new IllegalArgumentException("Can't pair one or less items.");
}
return PAIRS;
}
/**
* Helper for finding a random partner.
*
* @param key Object that needs partner.
* @return Unique partner that is not used by other keys.
*/
private Object getPartner(Object key) {
// Get random partner from array.
Object partner = items.get(getRandomInt(0, items.size() - 1));
// Cannot pair up a key with itself. Also partner cannot occur more than once.
if (key.equals(partner) || PAIRS.containsValue(partner)) {
partner = getPartner(key);
}
return partner;
}
/**
* Random integer in the given range.
*
* @param min Minimum value of the random integer.
* @param max Maximum value of the random integer.
* @return Random integer in given range.
*/
private static int getRandomInt(int min, int max) {
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
}
答案 0 :(得分:1)
更改此
for (String name : NAMES) {
if (!PAIRS.containsKey(name)) {
PAIRS.put(name, helper(name));
}
}
到
for (int i = 0; i < NAMES.length - 1; i++) {
String name = NAMES[i];
PAIRS.put(name, helper(name));
}
String name = NAMES[NAMES.length - 1];
if (PAIRS.containsValue(name)) {
PAIRS.put(name, helper(name));
} else {
String otherKey = NAMES[ThreadLocalRandom.current().nextInt(0, NAMES.length - 1)];
PAIRS.put(name, PAIRS.get(otherKey));
PAIRS.put(otherKey, name);
}
this answer中介绍了您的版本发生了什么变化。从本质上讲,您在最后一步没有选项,因此helper
会反复调用自己,直到StackOverflowError
发生。