【问题标题】:Java: Is there a data structure that works like a multimap but accepts duplicate keys?Java:是否有一种数据结构可以像多映射一样工作但接受重复的键?
【发布时间】:2009-12-28 04:45:36
【问题描述】:

我有点难过。本质上,我需要一个有点像数据库的数据结构。我需要能够为每个键拥有多个数据位,并且有可能拥有多个具有相同名称的键。然后我需要能够搜索该数据结构并提取正确的关键字并将其与其他可能的数据进行检查。这是一个例子:

Keys   |   Name   |  Price

Airplane | Boeing | 10000
Airplane | LearJet | 4000
Airplane | Airbus | 20000
Car | Honda | 500
Car | Ford | 450
Car | Chevy | 600

所以我需要能够专门搜索波音公司的飞机和飞机。由于很多原因,我不能使用实际的数据库,这完全是矫枉过正,因为我没有很多记录,但我确实需要能够提取这些值。我在 Java 中找到了一个 multimap 实现,但它不允许我插入多个具有相同名称的键,也不允许我不仅搜索键而且搜索具有相应值的键。

有人知道这可能是如何实现的吗? 谢谢

编辑:好的,我查看了所有答案。出于某种原因,我无法理解任何需要唯一键但正在使用地图的情况。这个解决方案有很多答案,我认为所有的错都是因为无法理解它们。 最终我需要拥有多个唯一键,我知道这些解决方案可以解决这个问题,但我就是无法理解它。

虽然它远不是一个完美的解决方案,但我使用了 Apache 的 MultiKey 类,因为我只需要提取一个可能的值,它就可以正常工作。我感谢每个人的努力,不幸的是我无法让它发挥作用。对不起

【问题讨论】:

  • 从您的 cmets 中可以明显看出,需要存储的项目很少。如果是这种情况,是不是使用更简单的东西,比如 List 或简单的 Map 并遍历要搜索的元素,真的会减慢您的应用程序的速度吗?
  • 缓慢根本不是问题。这可能需要永远,这不会是一个问题。我正在研究解决方案

标签: java oop data-structures map


【解决方案1】:

为什么不使用 Apache Commons 集合中的 MultiKey

http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/keyvalue/MultiKey.html

// populate map with data mapping key+name to price
Map map = new HashMap();
MultiKey multiKey = new MultiKey(key, name);
map.put(multiKey, price);

// later retireve the price
MultiKey multiKey = new MultiKey(key, name);
<Number> price = (String) map.get(price);

【讨论】:

  • 嗯,我喜欢这个解决方案。我不明白它是如何允许访问多个值的。
  • 我看到了问题。我倾向于从 PredicatedSortedMap 的角度来思考,但不确定编写一个谓词来比较 MultiKey 对象是否容易。
【解决方案2】:

为什么不用Set&lt;Entry&gt;

public class Entry {
   String key;
   List<Item>  items;
}
public class Item {
    String name;
    int  price;
}

【讨论】:

  • 使用它我将如何搜索项目?
  • 使用列表,您需要遍历项目。如果尺寸相当小(并且它是 O(n)),那应该没问题。否则,项目可以是 HashMap (以项目名称作为键)并且你有 O(1);如果沿着这条路走,你可以简单地取消 Item 和 store name 作为 key,price 作为 value。
  • 是的,看来最终我将不得不写一些东西来循环遍历多个键。
【解决方案3】:

您需要一个嵌套的Map。这是一个启动示例:

Map<String, Map<String, Integer>> vehicles = new HashMap<String, Map<String,Integer>>();
Map<String, Integer> airplanes = new HashMap<String, Integer>();
vehicles.put("Airplane", airplanes);
airplanes.put("Boeing", 10000);
airplanes.put("LearJet", 4000);
airplanes.put("Airbus", 20000);
Map<String, Integer> cars = new HashMap<String, Integer>();
vehicles.put("Car", cars);
cars.put("Honda", 500);
cars.put("Ford", 450);
cars.put("Chevy", 600);

// To get price of Airplane - Airbus, just do:
Integer price = vehicles.get("Airplane").get("Airbus");

【讨论】:

  • 我将不得不考虑这个解决方案,因为我的所有密钥都将被动态添加,并且我需要多个具有相同名称的密钥。
【解决方案4】:

您可以使用MapMaps。

【讨论】:

  • 我很难想象这项工作会如何。就像我如何搜索这两个项目一样
【解决方案5】:

在这种情况下,为什么不直接使用java.util.List

【讨论】:

    【解决方案6】:

    您当然可以使用 Java 的 Collections 来做到这一点,但这是真的,真的数据库的任务。

    您是否考虑过使用嵌入式数据库?它们允许您使用 DBMS 的所有功能,而实际上并不需要它(它们只是一个库)。看例如在 SQLite 或 HSQLDb 中。

    【讨论】:

    • 我不能再强烈反对了。就像我说的,我将在此表中包含很少的项目。完成所有为这件小事设置数据库的工作?我认为这很疯狂。就像用核武器杀死一只鸟一样。如果你在你的应用程序中做了很多这样的事情,是的,我可以看到它,但是想要处理所有这些事情真的需要很多
    【解决方案7】:

    为什么不直接使用像H2 这样的嵌入式数据库。然后,您可以使用一些简单的包装器(如 Spring 中的 SimpleJDBCTemplate)在 SQL 中执行搜索。或者,您可以为您的对象创建 ORM 映射并使用 HQL 或在映射的对象上搜索示例。

    【讨论】:

    • 好吧,因为这将是主要的矫枉过正。当您只打算对非常小的数据集使用此功能时,为什么还要在您的应用程序中嵌入数据库。对于很少的回报来说,这是很多麻烦。在这种情况下,它根本不是基于 Web 的应用程序,所以 Spring 是不可能的。
    • Spring 是针对 IoC 的,而不是专门针对 webapps 的。我之所以建议它,是因为 Spring-JDBC 包含包装器,通过封装大量样板代码,使 JDBC 连接的使用更加简单。如果您不喜欢仅嵌入内存的 DB 的想法,那么您可以研究使用带有 List 作为键而不是 String 的映射。
    • 是的,我明白 Spring 是为 IoC 设计的,它的开销太大了。这个程序太小了,要处理这一切真是令人头疼。在这一点上,我找到了一个可行的解决方案。我最终使用了堆栈而不是列表,这样我就不必搜索任何内容了。
    【解决方案8】:

    你的hashmap中的元素可以是一个arraylist或另一个hashmap。这样一键映射到多个整数。要搜索,您将查找第一个键,然后在结果中查找第二个键。查看BalusC's excellent example。根据您的评论,动态插入(如果它不知道何时添加了密钥)将类似于:

    Map<String,Integer> x = m.get("vehicle");
    if (x == null) {
      x = new HashMap<String,Integer>();
      m.put("vehicle", x);
    }
    x.put("mfg", 20000);
    

    可以创建一个 KeyPathMap 类,它在您请求它时返回一个地图 (getMap("vehicle")),并在您请求一个包含地图的路径时返回一个值 (get({"vehicle", "mfg", " key 3", "key 4", "key 5"})),类似于文件树。

    另一种方法是让您的密钥包含两个字符串。键可以是简单的串联(“Vehicle:Manufacturer”)或如下列表:

    List<String> k = Arrays.asList("vehicle", "manufacturer");
    map.put(k, 10000);
    ...
    map.get(k);
    

    您还可以使用带有 2 个字段的自定义键对象,这些字段基于 2 的串联进行散列(由 overriding hashCode and equals 完成;您的对象可以只委托给 internalString.hashCode 和 internalString.equals)。

    [从 cmets 移出]

    【讨论】:

      【解决方案9】:

      另一种多键实现可以在 Google 的 Collection Framework 中找到。看看javadoc。它也是 Apache V2 许可的。

      【讨论】:

        【解决方案10】:

        您可以使用 Google 的 Guava Table 集合来满足您的要求。

        Map<Keys,Map<Name,Price>> ==> Table<Keys,Name,Price>
        Map<Key1,Map<Key2,Value>> ==> Table<Key1,Key2,Value>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-26
          • 1970-01-01
          • 2012-11-04
          • 2013-10-08
          • 1970-01-01
          • 1970-01-01
          • 2011-04-25
          • 2023-03-24
          相关资源
          最近更新 更多