Java 集合之 Set

目录

1、基础操作 Basic Operations

2、批量操作 Bulk Operations


Set 集合是一个不能包含重复元素的集合。Set接口只包含从Collection继承的方法,并添加了禁止重复元素的限制。Set还为equals和hashCode操作的行为添加了更强的约定,允许对Set实例进行有意义的比较,即使它们的实现类型不同。如果两个Set实例包含相同的元素,则它们是相等的。

Java平台包含三种通用的集合实现:HashSet、TreeSet 和 LinkedHashSet。

  1. HashSet将其元素存储在哈希表中,是性能最好的实现;但是它不能保证迭代的顺序。
  2. TreeSet将元素存储在红黑树中,它根据元素的值对元素进行排序;它比HashSet慢得多。
  3. LinkedHashSet 的底层实现为哈希表+链表,它根据元素插入到集合的顺序对元素进行排序。LinkedHashSet 实现了元素排序,但代价比 HashSet 略高一些。

如果想要通过一个集合创建另一个包含相同元素的集合,但要消除所有重复项。可通过以下代码实现:

// c 表示原有集合
Collection<Type> noDups = new HashSet<Type>(c);

如果使用的是JDK8或更高版本,可以使用流操作:

c.stream()
    .collect(Collectors.toSet()); // no duplicates

如果使用的是 TreeSet,则通过以下方式进行设置:

Set<String> set = people.stream()
    .map(Person::getName)
    .collect(Collectors.toCollection(TreeSet::new));

下边程序使用了 LinkedHashSet,它保留了原始集合的顺序,同时删除了重复的元素:

Collection<Type> noDups = new LinkedHashSet<Type>(c);

下面是一个泛型方法,它封装了前面的用法,返回一个与传递的泛型类型相同的Set。

public static <E> Set<E> removeDups(Collection<E> c) {
    return new LinkedHashSet<E>(c);
}

1、基础操作 Basic Operations

  • size 操作返回集合中元素的个数。
  • isEmpty 判断指定的元素不存在,返回 true。
  • add 方法将元素添加到Set中,并返回一个布尔值,指示是否添加了该元素。
  • remove方法从Set中删除指定的元素,并返回一个布尔值。
  • iterator 方法返回一个遍历集合的迭代器。

下面的程序打印出参数列表中所有不同的单词。

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class FindDups {
    public static void main(String[] args) {
        args = "i came i saw i left".split(" ");
        Set<String> distinctWords = Arrays.asList(args).stream()
            .collect(Collectors.toSet());
        System.out.println(distinctWords.size() + " distinct words: " + distinctWords);
    }
}

执行结果:

4 distinct words: [left, came, saw, i]

注意,代码总是通过接口类型(Set)引用集合,而不是通过其实现类型。这是一种强烈推荐的编程实践,因为它提供了仅通过更改构造函数来更改实现的灵活性。

在上面的例子中,Set的实现类型是HashSet,它不保证Set中元素的顺序。如果希望程序按字母顺序打印单词列表,只需将Set的实现类型从HashSet更改为TreeSet。更改后执行结果如下:

4 distinct words: [came, i, left, saw]

2、批量操作 Bulk Operations

Set 同样适合于批量操作,假设 s1 和 s2 是 Set 集合。以下是批量操作的作用:

  • s1.containsAll(s2) — 如果s2是s1的子集,返回true
  • s1.addAll(s2) — 将s1变换为s1和s2的并集
  • s1.retainAll(s2) — 把s1变换成s1和s2的交集
  • s1.removeAll(s2) — 将s1转换为s1和s2的差集

如果要非破坏性地(不修改集合)计算两个集合的并、交或集差,调用方必须在调用批量操作之前复制一个集合。下边是习惯用法:

Set<Type> union = new HashSet<Type>(s1); // copy set
union.addAll(s2); // 并集

Set<Type> intersection = new HashSet<Type>(s1);
intersection.retainAll(s2); // 交集

Set<Type> difference = new HashSet<Type>(s1);
difference.removeAll(s2); // 差集

回到FindDups程序,需要统计参数列表中只出现过一次的单词和出现过多次的单词,同时不重复打印任何单词。

这个效果可以通过生成两个Set 集合来实现,一个包含参数列表中的每个单词,另一个只包含重复的单词。只出现一次的单词是这两个集合的集合差,我们知道如何计算。下面是结果程序的实现:

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

public class FindDups {

    public static void main(String[] args) {
        args = "i came i saw i left".split(" ");
        Set<String> uniques = new HashSet<String>();
        Set<String> dups = new HashSet<String>();
        for (String a : args) {
            if (!uniques.add(a)) {
                dups.add(a);
            }
        }
        // Destructive set-difference
        uniques.removeAll(dups);
        System.out.println("Unique words:    " + uniques);
        System.out.println("Duplicate words: " + dups);
    }
}

程序执行结果:

Unique words:    [left, came, saw]

Duplicate words: [i]

计算对称集合差

什么是对称集合差?即元素包含在两个指定集合中的任意一个,但不同时包含在两个集合中的元素集合。下面的代码非破坏性地计算两个集合的对称集差。

Set<Type> symmetricDiff = new HashSet<Type>(s1);
symmetricDiff.addAll(s2); // 1-先求并集
Set<Type> tmp = new HashSet<Type>(s1);
tmp.retainAll(s2); // 2-然后求交集
symmetricDiff.removeAll(tmp); // 3-最后求差集
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值