简体   繁体   English

随机访问 HashMap 个密钥

[英]Random access for HashMap keys

I need to randomly access keys in a HashMap. Right now, I am using Set 's toArray() method on the Set that HashMap 's keySet() returns, and casting it as a String[] (my keys are Strings).我需要随机访问 HashMap 中的键。现在,我在HashMap的 keySet() 返回的Set上使用Set的 toArray() 方法,并将其转换为 String[](我的键是字符串)。 Then I use Random to pick a random element of the String array.然后我使用Random从 String 数组中选择一个随机元素。

public String randomKey() {
    String[] keys = (String[]) myHashMap.keySet().toArray();
    Random rand = new Random();
    return keyring[rand.nextInt(keyring.length)];
}

It seems like there ought to be a more elegant way of doing this, I've read the following post.似乎应该有一种更优雅的方式来做到这一点,我已经阅读了以下帖子。 but it seems even more convoluted than the way I'm doing it, If the following solution is the better?但它似乎比我这样做的方式更令人费解,如果以下解决方案更好? why is that so?为什么? Selecting random key and value sets from a Map in Java 从 Java 中的 Map 中选择随机键和值集

There is no facility in a HashMap to return an entry without knowing the key so, if you want to use only that class, what you have is probably as good a solution as any. HashMap没有设施可在不知道键的情况下返回条目,因此,如果您只想使用该类,那么所拥有的解决方案可能与任何解决方案一样好。

Keep in mind however that you're not actually restricted to using a HashMap . 但是请记住,实际上您并不限于使用HashMap

If you're going to be reading this collection far more often than writing it, you can create your own class which contains both a HashMap of the mappings and a different collection of the keys that allows random access (like a Vector ). 如果你要来读这个集合的次数远远多于写它,你可以创建自己的类,它包含一个HashMap映射的和不同的集合,它允许随机访问(如按键的Vector )。

That way, you won't incur the cost of converting the map to a set then an array every time you read, it will only happen when necessary (adding or deleting items from your collection). 这样,您就不会在每次阅读时都将地图转换为集合然后转换为数组的成本它只会在必要时发生(在集合中添加或删除项目)。

Unfortunately, a Vector allows multiple keys of the same value so you would have to defend against that when inserting (to ensure fairness when selecting a random key). 不幸的是, Vector允许多个具有相同值的键,因此在插入时您必须对此加以防范(以确保选择随机键时的公平性)。 That will increase the cost of insertion. 这将增加插入成本。

Deletion would also be increased cost since you would have to search for the item to remove from the vector. 删除也将增加成本,因为您必须搜索要从向量中删除的项目。

I'm not sure there's an easy single collection for this purpose. 我不确定是否为此目的有一个简单的收藏。 If you wanted to go the whole hog, you could have your current HashMap , a Vector of the keys, and yet another HashMap mapping the keys to the vector indexes. 如果您想全力以赴,则可以使用当前的HashMap ,键的Vector另一个将键映射到矢量索引的HashMap

That way, all operations (insert, delete, change, get-random) would be O(1) in time, very efficient in terms of time, perhaps less so in terms of space :-) 这样,所有操作(插入,删除,更改,获取随机)在时间上都是O(1),在时间方面非常高效,而在空间方面则可能效率较低:-)

Or there's a halfway solution that still uses a wrapper but creates a long-lived array of strings whenever you insert, change or delete a key. 或者有一种中途解决方案仍然使用包装器,但是每当您插入,更改或删除键时都会创建一个长寿命的字符串数组。 That way, you only create the array when needed and you still amortise the costs. 这样,您仅在需要时创建阵列,而且仍可以摊销成本。 Your class then uses the hashmap for efficient access with a key, and the array for random selection. 然后,您的类使用哈希图通过键进行有效访问,并使用数组进行随机选择。

And the change there is minimal. 而且那里的变化很小。 You already have the code for creating the array, you just have to create your wrapper class which provides whatever you need from a HashMap (and simply passes most calls through to the HashMap ) plus one extra function to get a random key (using the array). 您已经具有创建数组的代码,只需创建包装器类即可提供HashMap所需的任何内容(并将大多数调用传递HashMap )以及一个额外的函数来获取随机密钥(使用数组) )。


Now, I'd only consider using those methods if performance is actually a problem though. 现在,如果性能实际上是一个问题,我只会考虑使用那些方法。 You can spend untold hours making your code faster in ways that don't matter :-) 您可以花费无数的时间以无关紧要的方式提高代码速度:-)

If what you have is fast enough, it's fine. 如果您拥有的足够快,那就没问题了。

Why not use the Collections.shuffle method, saved to a variable and simply pop one off the top as required. 为什么不使用Collections.shuffle方法,将其保存到变量,然后根据需要从顶部弹出一个。

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#shuffle(java.util.List) http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#shuffle(java.util.List)

You could avoid copying the whole keyset into a temporary data structure, by first getting the size, choosing the random index and then iterating over the keyset the appropriate number of times. 通过先获取大小,选择随机索引,然后在键集上进行适当的次数迭代,可以避免将整个键集复制到临时数据结构中。

This code would need to be synchronized to avoid concurrent modifications. 该代码将需要同步以避免并发修改。

If you really just want any element of a set, this will work fine.如果您真的只想要集合中的任何元素,这会很好用。

String s = set.iterator().next();

If you are unsure whether there is an element in the set, use:如果不确定集合中是否有元素,请使用:

String s;
Iterator<String> it = set.iterator();
if (it.hasNext()) {
    s = it.next();
}
else {
    // set was empty
}

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

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