【问题标题】:Creating a map with a collection as the Key?创建以集合为键的地图?
【发布时间】:2013-06-19 21:38:45
【问题描述】:

是否可以创建一个键是集合(任何类型的集合)的映射?

如果我在最常见的集合上尝试它,我会被告知该集合无法进行比较。

我一直在尝试为自定义集合编写 compareTo 函数,但我很挣扎。

要么我需要编写 compareTo,要么我需要找到一个预制的 Map 来接受 Maps 接受的集合/Collection。

如何将集合用作地图上的键?我已经查看过 Stack Overflow 并且我已经多次搜索过这个问题,但我从未找到一个可靠的解决方案!


我想这样做的原因是我用 Java 编写了一个模拟洗牌的“洗牌”模拟。我希望能够计算出特定手(建模为集合)出现的次数。它看起来像这样:

   H4,C3,D2: 8  
   H9,D6,S11: 10  
   ......

【问题讨论】:

  • 为什么要首先使用 Collection 作为键? Map 背后的整个概念是不可变键,而 Collections 直接违反了这个概念。
  • 这不是一个好主意,除非集合是只读的,否则它们很可能会改变,从而改变它们的 equals 和 hashCode 的行为,并且很可能很难给出结果预测何时检查键是否已存在或检索地图中的键。
  • 您可以使用 ArrayList 的 toString 方法将字符串用作键,或者您可以使用自定义格式化程序为您创建一个字符串,每次附加到字符串时,您都需要删除旧的字符串的条目。
  • @user962029 我确定我在更改 Card 和 Deck 类之前尝试过,但现在我已经更改了它我没有编写 compareTo 方法就没有尝试过......我一直在挣扎。

标签: java collections map comparable


【解决方案1】:

是否可以创建一个键是集合(任何类型的集合)的映射?

是的,这是可能的,但绝对不推荐。如果您的集合发生变化,它的哈希码很可能也会发生变化,这可能会导致令人惊讶的行为。

Map's javadoc:

注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是映射中的键,则不会指定映射的行为。


如果我在最常见的集合上尝试它,我会被告知该集合无法进行比较。

键不需要可比较,除非您使用排序映射,即 TreeMap。使用简单的 HashMap 就不会出现问题。


根据您的编辑,我将创建一个新的不可变 Hand 类:

class Hand implements Comparable<Hand> {
    private final List<Card> cards;
    Hand(Card c1, Card c2, Card c3) {
        cards = Collections.unmodifiableList(Arrays.asList(c1, c2, c3));
    }
    //getters, no setters
    //implement compareTo
}

如果你想在TreeSet&lt;Hand, Integer&gt; 中使用compareTo 并实施它,例如按手力排序。

【讨论】:

  • 同意必须注意确保密钥在用作密钥时不会发生变化。
  • 可以通过使用unmodifiable 集合作为键来缓解这种担忧吗?
  • @tieTYT 你只需要确保你没有修改密钥。一个不可修改的集合将强制执行。
  • @assylias 从技术上讲,它需要是不可修改的和副本。如果您只使用unmodifiableCollection(coll),您仍然可以修改基础集合。 :P
  • 在最后一次编辑中,我认为同时实现equalshashCode 是非常明智的,可能只需返回equalshashCode 字段的hashCode。 ..
【解决方案2】:

是的,您可以使用任何集合作为键。如果你想要一个像 TreeMap 这样的 SortedMap,你必须提供一个 Comparator 来确定顺序。但是,如果您使用任何不需要的 HashMap。

Map<List<Integer>, String> map = new HashMap<>();
map.put(Arrays.asList(1,2,3), "one to three");
map.put(Arrays.asList(7,8,9), "seven eat nine");
System.out.println(map);

打印

{[1, 2, 3]=one to three, [7, 8, 9]=seven eat nine}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2018-05-12
    • 1970-01-01
    相关资源
    最近更新 更多