我有一个场景,我将值存储在一个hashmap中。
键是
之类的字符串fruits
fruits_citrus_orange
fruits_citrus_lemon
fruits_fleshly_apple
fruits_fleshly
fruits_dry
等等。
值是一些对象。现在对于一个给定的输入说fruits_fleshly我需要检索所有以“fruits_fleshly”开头的情况 在上面的例子中,我需要获取
fruits_fleshly_apple
fruits_fleshly
执行此操作的一种方法是对所有键执行String.indexOf。有没有其他有效的方法来做到这一点,而不是迭代地图中的所有键
答案 0 :(得分:2)
迭代地图似乎是非常简单和直截了当的方式。但是,由于您不想自己迭代密钥,因此如果您可以使用第三方库,则可以使用Guava's Maps#filterEntries
。
以下是它的工作原理:
Map<String, Object> = Maps.filterEntries(
yourMap,
Predicate.containsPattern("^fruits_fleshly"));
但是,那也会在后院的地图上迭代。所以,如果你对效率感到困扰,迭代仍然存在。
答案 1 :(得分:2)
虽然这些是字符串,但对我来说,看起来这些是某些类别&amp;子类别,如水果,新鲜水果,水果柑橘等。
如果是这种情况,您可以改为实现Tree数据结构。这对搜索操作最有效。
由于Tree
具有父子结构,因此存在根节点&amp;子节点。你可以有这样的结构:
(0) (1) (2)
fruit
|_____citrus
| |_____lemon
| |_____orange
|
|_____freshly
|_____apple
|_____
在这种结构中,如果你想搜索柑橘类水果,你可以去柑橘,并列出它的所有孩子。最后,您可以通过将名称连接为从根到叶子的路径来构造全名。
答案 2 :(得分:1)
由于HashMap没有维护其键的任何顺序,因此对于这个问题不是一个很好的选择。更好的选择是TreeMap:它具有检索一系列键的子映射的方法。这些方法在O(log n)时间(n个条目)中运行,因此它比迭代密钥更好。
Map subMap = myMap.subMap("fruits_fleshly", true, "fruits_fleshly\uffff", true);
答案 3 :(得分:0)
散列映射的本质意味着无法对键进行“喜欢”比较 - 您必须遍历它们才能找到key.startsWith(input)
的位置。
我想你可以嵌套哈希映射并拆分密钥。例如,
{
"fruits":{
"citrus":{
"orange":(value),
"lemon":(value)
},
"fleshly":{
"apple":(value),
"":(value)
}
}
}
...等
性能影响可能在小范围内可怕,但在家庭作业环境中可能无关紧要,但如果您处理大量数据并且只有几层嵌套,则可能并不那么糟糕。
或者,使用List of Categories(子类别)和条目列表创建Category对象。
答案 4 :(得分:0)
我相信Radix Trie正是您所寻找的。它与@ ay89解决方案类似。
您可以使用此开源库Radix Trie example。它的性能优于O(log(N))。您将能够找到分配给密钥的平均常量时间(搜索关键字字符串中的下划线数)的散列图,并使用Radix Trie.fruits实现一个不错的实现 fruits_citrus_orange fruits_citrus_lemon fruits_fleshly_apple fruits_fleshly fruits_dry
Trie<String, Map> trie = new PatriciaTrie<>;
trie.put("fruits", hashmap1);
trie.put("fruits_citrus_orange", hashmap2);
trie.put("fruits_citrus_lemon", hashmap3);
trie.put("fruits_fleshly_apple", hashmap4);
trie.put("fruits_fleshly", hashmap5);
Map.Entry<String, Map> entry = trie.select("fruits_fleshy");
如果您只想通过select返回一个hashmap,那么如果您实现自己的Radix Trie,可能会获得更好的性能。