Set(集)

Set 是不重复元素的无序集,它主要关注元素是否在 Set 中,并具有两个特征:

  • 唯一性:其元素在 Set 内 是唯一的
  • 无序性:通常不能像 List 那样通过下标获取某个元素

对 Set 元素的遍历可以是无序,也可以是某方面有序的:

  • HashSet 是无序的
  • LinkedHashSet 按元素的写入顺序遍历
  • 有序 Set(如SplayTreeSet),按排序顺序进行遍历
classDiagram
  Set~E~ <|.. HashSet
  Set~E~ <|.. LinkedHashSet
  Set~E~ <|.. SetMixin~E~
  SetMixin~E~ <|-- SplayTreeSet~E~: with

  <<inferface>> Set
  <<final>> LinkedHashSet
  <<final>> HashSet
  <<final>> SplayTreeSet
  <<mixin>> SetMixin

Set 示例

先看一个简单的例子。

// ex641.dart

void main() {
  var fruites = {'Apple', 'Banana'}; // 1
  print(fruites.runtimeType); // Output: _Set<String>
  print(fruites); // Ouput: {Apple, Banana}

  fruites.add('Apple'); // 2
  print(fruites); // Ouput: {Apple, Banana}

  fruites.add('Cherry'); // 3
  print(fruites); // Ouput: {Apple, Banana, Cherry}

  print(fruites.length); // 4 Output: 3
}

  1. 使用字面量声明一个类型为Set 的变量 fruites ,它包含两个初始成员 'Apple' 和 'Banana';
  2. fruites添加一个成员Apple,由于Apple本来就已经在fruites Set中,因此这行代码执行后fruites的成员依旧只有原来的那两个;
  3. fruites追加一个新的成员Cherry,这样代码执行后,fruites一共包含了3个成员;
  4. fruites.length表示fruites的成员个数。

构造函数

Set 有如下工厂构造函数:

  • Set() 创建一个空的Set
  • Set.from(Iterable elements) 从一个Iterable对象创建Set,可理解为将一个Iterable对象转换为Set
  • Set.of(Iterable<E> elements)Set.from类似,区别在于前者返回的是Set<E>对象,即带有类型参数E
  • Set.identity() 创建一个空的 identity Set,该Set使用identical(Object?, Object?)函数对成员进行相等性测试
  • Set.unmodifiable(Iterable<E> elements)elements 创一个不可变Set

请阅读并分析下面的代码

// ex642.dart
import 'dart:math';

void main() {
  var list = [1, 2, 2, 3];

  var set1 = Set.from(list); // 1
  print('${set1.runtimeType} $set1'); // Output: _Set<dynamic> {1, 2, 3}

  var set2 = Set.of(list); // 2
  print('${set2.runtimeType} $set2'); // Output: _Set<int> {1, 2, 3}

  var a = Point(1, 2);
  var b = Point(1, 2);

  var set3 = Set.identity()
    ..add(a)
    ..add(b); // 3
  print(set3); // Output: {Point(1, 2), Point(1, 2)}

  var set4 = <dynamic>{}
    ..add(a)
    ..add(b); // 4
  print(set4); // Output: {Point(1, 2)}

  var set5 = Set.unmodifiable(set1);
  set5.add(5);
  // Unhandled exception:
  // Unsupported operation: Cannot change an unmodifiable set
}

Set特色方法

List一样,Set也实现了Iterable接口,即实现了Iterable接口定义的方法。由于在List章节中,我们已经对List的常用方法(包括Iterable接口中定义的方法)做了介绍,这里仅举例说明Set类型特有的方法。

// ex643.dart
void main() {
  var set1 = {1, 2, 3};
  var set2 = {2, 3, 4};

  var set3 = set1.union(set2); // 1
  print(set3); // Output: {1, 2, 3, 4}

  var set4 = set1.intersection(set2); // 2
  print(set4); // Output: {2, 3}

  var set5 = set1.difference(set2); // 3
  print(set5); // Output: {1}

  var set6 = set2.difference(set1); // 3a
  print(set6); // Output: {4}

  var a = set1.lookup(1); // 4
  print(a); // Output: 1

  var b = set1.lookup(4); // 4a
  print(b); // Output: null
}
  1. union(Set<E> other) 返回该Set与另一个Set(other)的并集;
  2. intersection(Set<Object?> other) 返回该Set与另一个Set(other)的交集;
  3. difference(Set<Object?> other) 返回该Set与另一个Set(other) 的差集,注意 this.difference(other)other.difference(this)是不同的;
  4. lookup(Object? object):如果Set中的某个成员与给定的对象object相等,就返回该成员,否则返回null

关于Set的更多方法,请查阅官方文档