【问题标题】:Get a value from hashtable by a part of its key通过其键的一部分从哈希表中获取值
【发布时间】:2010-06-10 13:01:17
【问题描述】:

假设我有一个 Hashtable<String, Object> 具有这样的键和值:

apple => 1
orange => 2
mossberg => 3

我可以使用标准的get 方法通过“apple”获取1,但我想要的是通过键的一部分获取相同的值(或值列表),例如“ppl”。当然它可能会产生几个结果,在这种情况下,我希望能够处理每个键值对。所以基本上类似于LIKE '%ppl%' SQL 语句,但我不想仅仅因为不想增加不必要的复杂性而使用(内存中)数据库。你会推荐什么?

更新: 在 Hashtable 中存储数据不是必需的。我正在寻找一种通用的方法来解决这个问题。

【问题讨论】:

  • 这个问题听起来类似于全文搜索——自 70 年代以来就已经存在这样的算法。不过,我不确定将它们应用于动态数据结构会有多困难。

标签: java hashtable


【解决方案1】:

显而易见的蛮力方法是遍历映射中的键并将它们与 char 序列进行匹配。这对于一张小地图来说可能没问题,但它当然不能按比例缩放。

这可以通过使用第二个地图缓存搜索结果来改善。每当您收集与给定字符序列匹配的键列表时,您都可以将它们存储在第二个映射中,以便下次查找快速。当然,如果原始地图经常更改,更新缓存可能会变得复杂。与缓存一样,如果地图的读取次数多于更改次数,则效果最佳。

或者,如果您事先知道可能的字符序列,您可以预先生成匹配字符串的列表并预先填充您的缓存映射。

更新: 无论如何都不推荐Hashtable - 它是同步的,因此比它应该的要慢得多。如果不涉及并发,最好使用HashMap,否则使用ConcurrentHashMap。后者的性能远远优于Hashtable

除此之外,我想不出比地图更好的集合来完成这项任务。当然,您可以尝试不同的地图实现,以找到最适合您的具体情况和使用模式的一种。一般情况下是这样的

Map<String, Object> fruits;
Map<String, List<String>> matchingKeys;

【讨论】:

  • @htf,检查并回答 :-)
  • 当然 - 我对使用缓存来加速基于不适当数据结构的实现的设计方法提出了质疑,当随机访问数据时甚至不能保证加速时。使用旨在解决问题的数据结构总是比将方形钉锤入圆孔然后在其上涂漆要好。我取消了我的反对票,因为除了一些研究方向之外,我没有更好的解决方案可以提供(我会查看尝试和后缀树,我提出了一个使用 trie 的解决方案,但没有指向完全适用的实现的指针。)
  • @Ori,虽然我不完全同意你投反对票的理由,但你玩的很公平 :-) 谢谢你的解释,学习新东西总是很有趣的。
【解决方案2】:

没有明确地迭代。 Hashtable 被设计为在 O(1) 中(精确)键-> 值,仅此而已。如果您将使用大量数据进行查询操作,我建议您考虑使用数据库。您可以使用像SQLite(参见SQLiteJDBC)这样的嵌入式系统,因此不需要单独的进程或安装。然后您可以选择database indexes

我知道没有标准的 Java 集合可以有效地执行这种类型的操作。

【讨论】:

    【解决方案3】:

    听起来您需要一个引用您的数据的 trie。 trie 存储字符串并允许您按前缀搜索字符串。我不太了解 Java 标准库,也不知道它是否提供了实现,但这里有一个:

    http://www.cs.duke.edu/~ola/courses/cps108/fall96/joggle/trie/Trie.java

    不幸的是,trie 只能让您按前缀进行搜索。您可以通过存储每个键的所有可能后缀来解决此问题:

    对于“苹果”,您需要存储字符串

    '苹果' '苹果' '请' '乐' 'e'

    这将允许您搜索键的每个后缀的每个前缀。

    诚然,这种“解决方案”会促使我继续寻找其他选择。

    【讨论】:

      【解决方案4】:

      首先,使用 hashmap,而不是 hashtable。

      然后,您可以使用google guava 中的实用程序filter the map using a predicate

      public Collection<Object> getValues(){
          Map<String,Object> filtered = Maps.filterKeys(map,new Predicate<String>(){
              //predicate methods
          });
          return filtered.values();
      }
      

      【讨论】:

        【解决方案5】:

        不能一次完成

        您可能想尝试迭代键并使用包含所需字符串的键。

        【讨论】:

          【解决方案6】:

          我能看到的唯一解决方案(我不是 Java 专家)是遍历键并检查是否与正则表达式匹配。如果匹配,则将匹配的键值对放入将返回的哈希表中。

          【讨论】:

            【解决方案7】:

            如果您能以某种方式将问题简化为按前缀搜索,您可能会发现NavigableMap 很有帮助。

            【讨论】:

            • 我猜在任何可能的解决方案中,按前缀搜索都会大大减少需要执行的操作数量。
            【解决方案8】:

            你会觉得抛出这些问题会很有趣:Fuzzy string search library in Java

            也看看 Lucene(答案二)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-04-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-07-28
              • 2021-09-21
              • 2012-11-21
              • 2012-08-17
              相关资源
              最近更新 更多