如何在Java中维护唯一列表?

2022-08-31 08:46:48

如何在Java中创建唯一/不同对象(无重复)的列表?

现在我正在使用这样做,因为密钥被覆盖了,因此在最后我们可以获得唯一的密钥。但我相信应该有更好的方法来做到这一点,因为价值部分在这里被浪费了。HashMap<String, Integer>HashMap.getKeySet()


答案 1

您可以使用 Set 实现:

来自 JAVADoc 的一些信息:

不包含重复元素的集合。更正式地说,集合不包含一对元素 e1 和 e2 使得 e1.等于(e2),并且最多有一个 null 元素。顾名思义,这个接口对数学集合抽象进行建模。

注意:如果将可变对象用作集合元素,则必须格外小心。如果对象的值的更改方式会影响相等比较,而对象是集合中的元素,则不会指定集合的行为。这种禁止的一个特殊情况是,不允许集合将自身作为元素包含。

这些是实现:

  • 哈希集

    此类为基本操作(添加、删除、包含和大小)提供恒定的时间性能,前提是哈希函数在存储桶中正确分散元素。迭代此集所需的时间与 HashSet 实例的大小(元素数)加上支持 HashMap 实例的“容量”(存储桶数)之和成正比。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或负载因子太低)非常重要。

    迭代 a 时,生成的元素的顺序是未定义的。HashSet

  • LinkedHashSet

    Set 接口的哈希表和链表实现,具有可预测的迭代顺序。此实现与 HashSet 的不同之处在于,它维护一个运行其所有条目的双链表。此链表定义迭代顺序,即元素插入到集合中的顺序(插入顺序)。请注意,如果将元素重新插入到广告集中,广告订单不受影响。(如果调用 s.add(e), 则元素 e 将重新插入到集合 s 中,而 s.contains(e) 将在调用前立即返回 true。

    那么,上面代码的输出...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }
    

    ...必然会

    3
    1
    2
    
  • 树集

    此实现为基本操作(添加、删除和包含)提供有保证的 log(n) 时间成本。默认情况下,迭代时返回的元素按其“自然排序”排序,因此上面的代码...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }
    

    ...将输出以下内容:

    1
    2
    3
    

    (还可以将实例传递给构造函数,使其以不同的顺序对元素进行排序。ComparatorTreeSet

    请注意,如果要正确实现 Set 接口,则由集合维护的排序(无论是否提供显式比较器)必须与 equals 一致。(有关与等数一致的精确定义,请参见“比较”或“比较器”。之所以如此,是因为 Set 接口是根据 equals 运算定义的,但 TreeSet 实例使用其 compareTo(或 compare)方法执行所有元素比较,因此从集合的角度来看,此方法视为相等的两个元素是相等的。集合的行为是明确定义的,即使它的顺序与等数不一致;它只是不遵守 Set 接口的总协定。


答案 2

我想在这里为原始海报澄清一些事情,其他人已经提到过,但并没有真正明确说明。当你说你想要一个唯一列表时,这就是有序集的定义。“设置接口”和“列表”接口之间的其他一些主要区别是 List 允许您指定插入索引。所以,问题是你是否真的需要列表接口(即与第三方库的兼容性等),或者你可以重新设计你的软件来使用Set接口?您还必须考虑您正在对界面执行的操作。按索引查找元素是否重要?你期望在你的集合中有多少元素?如果您要拥有许多元素,那么排序是否重要?

如果你真的需要一个只有唯一约束的列表,有Apache Common Utils类org.apache.commons.collections.list.SetUniqueList,它将为您提供List接口和唯一的约束。请注意,这会破坏列表界面。但是,如果您需要按索引查找列表,则可以从中获得更好的性能。如果您可以处理 Set 接口,并且数据集较小,那么 LinkedHashSet 可能是一个不错的方法。这只取决于软件的设计和意图。

同样,每个集合都有一定的优点和缺点。有些快速插入但读取速度慢,有些具有快速读取但插入缓慢等。花相当多的时间在集合文档上,以充分了解每个类和接口的更精细的细节是有意义的。