我有一个HashMap,每当我得到迭代器时,我想以不同的随机顺序迭代它们的键值对。从概念上讲,我想在调用迭代器之前“洗牌”地图(或者如果你想要,“洗牌”迭代器)。
我有两种选择:
1)使用LinkedHashMap的方法并在内部保留一个条目列表,将其随地移动并在调用迭代器时返回该视图。
2)取map.entrySet(),构造一个ArrayList并在其上使用shuffle()。
虽然这两种方法看起来与我类似,但我期待非常大的HashMaps,所以我真的很关心细节和内部,因为我真的不能浪费内存或计算。
答案 0 :(得分:9)
重新整理大型藏品总是很昂贵。每个条目至少需要一个引用。例如对于100万个条目,您将需要大约4 MB。
请注意; shuffle操作是O(N)
我会用
Map<K,V> map =
List<Map.Entry<K,V>> list = new ArrayList<Map.Entry<K,V>>(map.entrySet());
// each time you want a different order.
Collections.shuffle(list);
for(Map.Entry<K, V> entry: list) { /* ... */ }
答案 1 :(得分:0)
实际上你根本不需要洗牌:
只需在一组键中绘制一个随机索引,然后通过覆盖最后一个键来删除该键:
public class RandomMapIterator<K,V> implements Iterator<V> {
private final Map<K,V> map;
private final K[] keys;
private int keysCount;
@SuppressWarnings("unchecked")
public RandomMapIterator(Map<K,V> map) {
this.map = map;
this.keys = (K[]) map.keySet().toArray();
this.keysCount = keys.length;
}
@Override
public boolean hasNext() {
return keysCount!=0;
}
@Override
public V next() {
int index = nextIndex();
K key = keys[index];
keys[index] = keys[--keysCount];
return map.get(key);
}
protected int nextIndex() {
return (int)(Math.random() * keysCount);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
答案 2 :(得分:-2)
尝试使用concurent哈希映射并在迭代周期之前随机获取密钥
Map<String, String> map = Maps.newConcurrentMap();
map.put("1", "1");
map.put("2", "2");
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
map.remove("2");// add random key values
map.put("2", "2");
String next = iterator.next();
System.out.println("next" + next);
}
随机删除/放置值可以“改变”地图