从Java中的Map中选择随机键和值集

时间:2012-03-29 05:48:02

标签: java dictionary random hashmap treemap

我想从Map获取随机密钥及其各自的值。这个想法是随机生成器会选择一个键并显示该值。棘手的部分是键和值都是字符串,例如myMap.put("Geddy", "Lee")

8 个答案:

答案 0 :(得分:48)

HashMap<String, String> x;

Random       random    = new Random();
List<String> keys      = new ArrayList<String>(x.keySet());
String       randomKey = keys.get( random.nextInt(keys.size()) );
String       value     = x.get(randomKey);

答案 1 :(得分:4)

这个问题应该对您Is there a way to get the value of a HashMap randomly in Java?提供帮助,而且Picking a random element from a set也应该HashMapHashSet支持O(n)。它可以是O(n)时间和恒定空间,也可以是{{1}}额外空间和恒定时间。

答案 2 :(得分:3)

如果您不介意浪费的空间,一种方法是分别保留List中所有密钥的Map。为获得最佳性能,您需要具有良好随机访问性能的List(如ArrayList)。然后,只需获取0(包括)和list.size()(不包括)之间的随机数,拉出该索引处的键,然后查看该键。

Random rand = something
int randIndex = rand.nextInt(list.size());
K key = list.get(randIndex);
V value = map.get(key);

这种方法也意味着添加键值对比删除键值更便宜。要添加键值对,您需要测试该键是否已在地图中(如果您的值可以为null,则必须单独调用map.containsKey;如果不是,则只需添加键值对并查看它返回的“旧值”是否为null)。如果键已经在映射中,则列表不会更改,但如果不是,则将键添加到列表中(O( 1)大多数列表的操作。但是,删除键值对涉及O(N)操作以从列表中删除键。

如果空间是一个很大的问题,但性能不是很好,你也可以在地图的入口集(Iterator)上获得Map.entrySet(),并在返回之前跳过randIndex条目一个你想要的。但这将是一个O(N)操作,它有点击败了地图的整个点。

最后,您可以获取条目集toArray()并随机索引。这更简单,但效率更低。

答案 3 :(得分:2)

如果你的键是整数或类似的东西,你可以使用TreeMap来做到这一点。

TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int key = RandomUtils.ranInt(treeMap.lastKey());
int value = treeMap.ceilingKey(key);

答案 4 :(得分:1)

我会将Map复制到一个数组中并随机选择你想要的条目。这样就无需从密钥中查找值。

Map<String, String> x = new HashMap<String, String>();
Map.Entry<String,String>[] entries = x.entrySet().toArray(new Map.Entry[0]);
Random rand = new Random();

// call repeatedly
Map.Entry<String, String> keyValue = entries[rand.nextInt(entries.length)];

如果您想避免重复,可以随机化条目的顺序

Map<String, String> x = new HashMap<String, String>();
List<Map.Entry<String,String>> entries = new ArrayList<Map.Entry<String, String>> (x.entrySet());
Collections.shuffle(entries);
for (Map.Entry<String, String> entry : entries) {
    System.out.println(entry);
}

答案 5 :(得分:1)

使用reservoir sampling选择随机键列表,然后将它们插入地图(以及源地图中的相应值)。

这样您就不需要将整个keySet复制到数组中,只需复制选定的键。

public static <K, V>Map<K, V> sampleFromMap(Map<? extends K, ? extends V> source, int n, Random rnd) {
    List<K> chosenKeys = new ArrayList<K>();
    int count = 0;
    for (K k: source.keySet()) {
        if (count++ < n) {
            chosenKeys.add(k);
            if (count == n) {
                Collections.shuffle(chosenKeys, rnd);
            }
        } else {
            int pos = rnd.nextInt(count);
            if (pos < n) {
                chosenKeys.set(pos, k);
            }
        }
    }
    Map<K, V> result = new HashMap<K, V>();
    for (K k: chosenKeys) {
        result.put(k, source.get(k));
    }
    return Collections.unmodifiableMap(result);
}

答案 6 :(得分:0)

toolbox.router.get('/(.)', toolbox.fastest);
toolbox.router.post('/(.)', toolbox.fastest);
toolbox.router.get('/(.)', toolbox.fastest, {origin: 'https://example.cloudfront.net'})
toolbox.router.get('/(.)', toolbox.fastest, {origin: 'https://example.in'})

答案 7 :(得分:-1)

自从玩过java以来​​已经有一段时间了,但是keySet()没有给你一个可以使用数字索引选择的列表吗?我想你可以选择一个随机数并从myMap的keySet中选择,然后从myMap中选择相应的值。现在无法测试,但它似乎尽可能地打击我!

相关问题