118

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

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

4

7 回答 7

190

您可以使用Set实现:

来自 JAVADoc 的一些信息:

不包含重复元素的集合。更正式地说,集合不包含一对元素 e1 和 e2 使得 e1.equals(e2),并且最多包含一个空元素。正如它的名字所暗示的,这个接口模拟了数学集合抽象。

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

这些是实现:

  • 哈希集

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

    迭代 aHashSet时,产生的元素的顺序是未定义的。

  • 链接哈希集

    Set 接口的哈希表和链表实现,具有可预测的迭代顺序。此实现与 HashSet 的不同之处在于它维护一个双向链表,该列表贯穿其所有条目。该链表定义了迭代顺序,即元素插入集合的顺序(插入顺序)。请注意,如果将元素重新插入集合中,则插入顺序不受影响。(如果 s.add(e) 被调用,而 s.contains(e) 将在调用之前立即返回 true,则元素 e 被重新插入到集合 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 一致。(参见 Comparable 或 Comparator 以获得与 equals 一致的精确定义。)这是因为 Set 接口是根据 equals 操作定义的,但是 TreeSet 实例使用其 compareTo(或 compare)方法执行所有元素比较,所以两个从集合的角度来看,这种方法认为相等的元素是相等的。一个集合的行为是明确定义的,即使它的顺序与equals不一致;它只是不遵守 Set 接口的一般约定。

于 2012-11-06T21:18:05.053 回答
16

我想在这里澄清一些其他人已经提到但没有真正明确说明的原始海报。当你说你想要一个唯一列表时,这就是有序集的定义。Set 接口和 List 接口之间的其他一些关键区别是 List 允许您指定插入索引。所以,问题是你真的需要 List 接口(即为了与 3rd 方库的兼容性等),还是你可以重新设计你的软件来使用 Set 接口?您还必须考虑使用界面做什么。通过索引查找元素重要吗?你期望你的集合中有多少元素?如果你有很多元素,排序重要吗?

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

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

于 2014-12-14T18:23:50.653 回答
11

使用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);

  }
}
于 2012-11-06T21:18:29.197 回答
5

我不知道这有多有效,但是在简单的上下文中对我有用。

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

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }
于 2018-06-28T07:49:06.343 回答
4

您可以只使用 aHashSet<String>来维护唯一对象的集合。如果Integer你的 map 中的值很重要,那么你可以使用containsKeymaps 的方法来测试你的 key 是否已经在 map 中。

于 2012-11-06T21:17:13.023 回答
3

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

这是HashSet 的javadoc

于 2012-11-06T21:17:05.590 回答
1

您可能希望使用java.util.Set<E>接口的实现类之一,例如java.util.HashSet<String> 集合类。

不包含重复元素的集合。更正式地说,集合不包含一对元素 e1 和 e2 使得 e1.equals(e2),并且最多包含一个空元素。正如它的名字所暗示的,这个接口模拟了数学集合抽象。

于 2012-11-06T21:17:01.990 回答