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


104

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

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

Answers:


164

您可以使用Set实现:

来自JAVADoc的一些信息:

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

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

这些是实现:

  • 哈希集

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

    迭代HashSet时,产生元素的顺序是不确定的。

  • 链接哈希集

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

    因此,上面代码的输出...

     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

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

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


现在我很困惑,应该使用哪一个?我只需要维护一个唯一字符串列表。因此,基本上,即使添加了现有字符串,也应该实际添加它。

1
选择是您自己的... HashSet是通用且快速的,树集是有序的,LinkedHashset保持插入顺序...
Frank

6
这不是LIST ...,因此,并非所有LIST接口方法都可用。
marcolopes

2
集合不是列表,我无法在O(1)时间(随机访问)中按索引查找集合中的元素。
wilmol

13

我想在这里澄清原始海报的一些内容,其他人已经提及但没有明确说明。当您说想要唯一列表时,这就是有序集的定义。Set接口和List接口之间的其他一些关键区别是List允许您指定插入索引。因此,问题是您是否真的需要列表接口(即与第三方库的兼容性等),还是可以重新设计软件以使用Set接口?您还必须考虑界面的操作。通过索引查找元素是否重要?您期望集合中有多少个元素?如果您要包含许多元素,那么订购是否重要?

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

同样,每个集合都有某些优点和缺点。一些快速插入但读取速度慢,有些快速读取但插入速度慢,等等。在集合文档中花大量时间以充分了解每个类和接口的详细信息是有意义的。


3
这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论-您可以随时对自己的帖子发表评论,一旦您拥有足够的声誉,就可以在任何帖子中发表评论
Zach Saucier 2014年

1
实际上,它确实提供了答案。如果他只想要一个像Set一样的列表,请使用org.apache.commons.collections.list.SetUniqueList,但作为一名程序员,他/我们应该比那时更加小心,并且应该多考虑问题。如果这使我的回答更好,“如何在Java中创建唯一列表?” 清单uniqueList = new SetUniqueList();就是这样...
Paul Connolly

3
Zach,我不是想成为一个混蛋,但您在发表评论之前甚至还阅读了我的回答吗?还是您只是不了解?如果您不理解,那就可以了-让我知道,我将继续讨论这个话题。我认为不必为了对某个人的问题给出友好的回答而在数据结构上写一篇论文。当我知道答案并且没有人真正提供答案时,我也不希望采取任何温柔的方式来建立我的评论声誉。
Paul Connolly 2014年

1
顺便说一句,我既没有提出批评,也没有要求作者澄清,我只是说他可以A)快速使用我给他的课程,或者B)花时间真正地理解这些课程之间的区别并建立联系他们到他的需要。B显然需要更长的时间,但从长远来看会带来更好的代码。
Paul Connolly 2014年

8

使用new HashSet<String> 一个例子:

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}

2
只需添加上述程序的内容->必须发送11封信至:[亚伦,爱丽丝,詹姆斯,阿德尔,何塞,杰里米,艾米,艾伦,帕特里克,海伦,亚历克斯]
Ammad

4

您可以使用A HashSet<String>来维护唯一对象的集合。如果Integer地图中的值很重要,则可以改用containsKey地图方法来测试密钥是否已在地图中。


3

HashSet<String>(或)任何Set实现都可以为您完成这项工作。Set不允许重复。

这是HashSet的javadoc


2

我不知道这有多有效,但是在简单的环境下对我有用。

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }

1

您可能要使用java.util.Set<E>Interface 的实现类之一,例如java.util.HashSet<String> collection类。

不包含重复元素的集合。更正式地讲,集合不包含元素对e1和e2,使得e1.equals(e2)最多包含一个空元素。顾名思义,此接口对数学集合抽象进行建模。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.