简体   繁体   English

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

[英]Selecting random key and value sets from a Map in Java

I want to get random keys and their respective values from a Map. 我想从Map获取随机密钥及其各自的值。 The idea is that a random generator would pick a key and display that value. 这个想法是随机生成器会选择一个键并显示该值。 The tricky part is that both key and value will be strings, for example myMap.put("Geddy", "Lee") . 棘手的部分是键和值都是字符串,例如myMap.put("Geddy", "Lee")

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);

This question should be of help to you Is there a way to get the value of a HashMap randomly in Java? 这个问题应该对你有所帮助有没有办法在Java中随机获取HashMap的值? and this one also Picking a random element from a set because HashMap is backed by a HashSet . 这个也从一个集中挑选一个随机元素,因为HashMap由一个HashSet支持。 It would be either O(n) time and constant space or it would be O(n) extra space and constant time. 它可以是O(n)时间和恒定空间,也可以是O(n)额外空间和恒定时间。

If you don't mind the wasted space, one approach would be to separately keep a List of all keys that are in the Map . 如果您不介意浪费的空间,一种方法是单独保留Map中所有键的List For best performance, you'll want a List that has good random-access performance (like an ArrayList ). 为了获得最佳性能,您需要一个具有良好随机访问性能的List (如ArrayList )。 Then, just get a random number between 0 (inclusive) and list.size() (exclusive), pull out the key at that index, and look that key up. 然后,只需获取0(包括)和list.size() (不包括)之间的随机数,拉出该索引处的键,然后查看该键。

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

This approach also means that adding a key-value pair is a good deal cheaper than removing one. 这种方法还意味着添加键值对比删除键值更便宜。 To add the key-value pair, you would test to see if the key is already in the map (if your values can be null, you'll have to separately call map.containsKey ; if not, you can just add the key-value pair and see if the "old value" it returns is null) . 要添加键值对,您将测试键是否已经在地图中(如果您的值可以为null,则必须单独调用map.containsKey ;如果不是,您只需添加键 -值对并查看它返回的“旧值”是否为null) If the key is already in the map, the list is unchanged, but if not, you add the key to the list (an O(1) operation for most lists). 如果密钥已经在映射中,则列表不会更改,但如果不是,则将密钥添加到列表中(对于大多数列表,操作为O(1))。 Removing a key-value pair, though, involves an O(N) operation to remove the key from the list. 但是,删除键值对涉及O(N)操作以从列表中删除键。

If space is a big concern, but performance is less so, you could also get an Iterator over the map's entry set ( Map.entrySet() ), and skip randIndex entries before returning the one you want. 如果空间是一个很大的问题,但性能不那么重要,你也可以在地图的入口集( Map.entrySet() )上获得一个Iterator ,并在返回你想要的randIndex之前跳过randIndex条目。 But that would be an O(N) operation, which kinda defeats the whole point of a map. 但这将是一个O(N)操作,它有点击败了地图的整个点。

Finally, you can just get the entry set's toArray() and randomly index into that. 最后,你可以得到条目集的toArray()并随机索引到那个。 That's simpler, though less efficient. 这更简单,但效率更低。

if your keys are integer, or something comparable, you can use TreeMap to do that. 如果你的键是整数或类似的东西,你可以使用TreeMap来做到这一点。

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

I would copy the Map into an array and select the entry you want at random. 我会将Map复制到一个数组中,然后随机选择你想要的条目。 This avoid the need to also lookup the value from the key. 这样就无需从密钥中查找值。

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)];

If you want to avoid duplication, you can randomize the order of the entries 如果要避免重复,可以随机化条目的顺序

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);
}

Use reservoir sampling to select a list of random keys, then insert them into a map (along with their corresponding values in the source map.) 使用油藏采样选择随机键列表,然后将它们插入地图(以及源地图中的相应值)。

This way you do not need to copy the whole keySet into an array, only the selected keys. 这样您就不需要将整个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);
}
In some cases you might want to preserve an order you put the elements in the Set,
In such scenario you can use, This 

Set<Integer> alldocsId = new HashSet<>();
            for (int i=0;i<normalized.length;i++)
            {
                String sql = "SELECT DISTINCT movieID FROM postingtbl WHERE term=?";
                PreparedStatement prepstm = conn.prepareStatement(sql);
                prepstm.setString(1,normalized[i]);
                ResultSet rs = prepstm.executeQuery();
                while (rs.next())
                {
                    alldocsId.add(rs.getInt("MovieID"));
                }
                prepstm.close();
            }

        List<Integer> alldocIDlst = new ArrayList<>();
        Iterator it = alldocsId.iterator();
        while (it.hasNext())
        {
            alldocIDlst.add(Integer.valueOf(it.next().toString()));
        }

Been a while since a played with java, but doesn't keySet() give you a list that you can select from using a numerical index? 自从玩过java以来​​已经有一段时间了,但是keySet()没有给你一个可以使用数字索引选择的列表吗? I think you could pick a random number and select that from the keySet of myMap, then select the corresponding value from myMap. 我想你可以选择一个随机数并从myMap的keySet中选择,然后从myMap中选择相应的值。 Can't test this right now, but it seems to strike me as possible! 现在无法测试,但它似乎尽可能地打击我!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM