Dart HashSet
最后修改于 2025 年 4 月 4 日
在 Dart 中,HashSet 是一个包含唯一元素的无序集合。它使用哈希表提供快速的查找、添加和删除操作。
HashSet 实现了 Set 接口,并要求元素具有一致的 Object.==
和 Object.hashCode
实现。不允许重复元素。
创建 HashSet
创建 HashSet 的最简单方法是使用构造函数。我们可以指定元素类型和可选的相等比较器。
import 'dart:collection'; void main() { var colors = HashSet<String>(); colors.add('red'); colors.add('green'); colors.add('blue'); colors.add('red'); // Duplicate ignored print(colors); }
我们创建一个颜色 HashSet。泛型类型指定了 String 元素。我们使用 add() 添加元素,重复项会被自动忽略。
$ dart main.dart {red, green, blue}
从 Iterable 创建 HashSet
我们可以使用 HashSet.from 构造函数从现有的 Iterable 创建 HashSet。这会自动删除重复项。
import 'dart:collection'; void main() { var numbers = [1, 2, 3, 2, 4, 1, 5]; var uniqueNumbers = HashSet.from(numbers); print('Original: $numbers'); print('Unique: $uniqueNumbers'); }
这会从一个包含重复项的列表中创建一个 HashSet。结果 HashSet 只包含原始列表中的唯一值。
$ dart main.dart Original: [1, 2, 3, 2, 4, 1, 5] Unique: {1, 2, 3, 4, 5}
检查内容
HashSet 提供了检查元素是否存在和集合状态的方法。这些操作通常具有 O(1) 的复杂度。
import 'dart:collection'; void main() { var primes = HashSet.from([2, 3, 5, 7, 11]); print(primes.contains(5)); // true print(primes.contains(4)); // false print(primes.isEmpty); // false print(primes.length); // 5 print(primes.first); // 2 (arbitrary) }
我们检查 HashSet 的各种属性。第一个元素是任意的,因为 HashSet 不维护插入顺序。
$ dart main.dart true false false 5 2
集合操作
HashSet 支持标准的集合操作,如联合、交集和差集。这些方法返回新的集合,而不会修改原始集合。
import 'dart:collection'; void main() { var setA = HashSet.from([1, 2, 3, 4]); var setB = HashSet.from([3, 4, 5, 6]); print('Union: ${setA.union(setB)}'); print('Intersection: ${setA.intersection(setB)}'); print('Difference: ${setA.difference(setB)}'); }
我们演示了三种基本的集合操作。每种操作都会创建一个包含该操作结果的新 HashSet。
$ dart main.dart Union: {1, 2, 3, 4, 5, 6} Intersection: {3, 4} Difference: {1, 2}
遍历 HashSet
我们可以使用各种方法遍历 HashSet 元素。迭代顺序是未定义的,但对于同一个集合是稳定的。
import 'dart:collection'; void main() { var languages = HashSet.from(['Dart', 'Java', 'Python', 'Go']); print('For loop:'); for (var lang in languages) { print(lang); } print('\nForEach:'); languages.forEach((lang) => print(lang)); print('\nIterator:'); var it = languages.iterator; while (it.moveNext()) { print(it.current); } }
这演示了遍历 HashSet 的三种方法。对于给定的集合,所有方法都将以相同的(任意)顺序处理元素。
$ dart main.dart For loop: Dart Java Python Go ForEach: Dart Java Python Go Iterator: Dart Java Python Go
移除元素
HashSet 提供了单独删除元素或清空整个集合的方法。这些操作通常具有 O(1) 的复杂度。
import 'dart:collection'; void main() { var fruits = HashSet.from(['apple', 'banana', 'orange', 'kiwi']); print('Original: $fruits'); fruits.remove('banana'); print('After remove: $fruits'); fruits.removeWhere((fruit) => fruit.length > 5); print('After removeWhere: $fruits'); fruits.clear(); print('After clear: $fruits'); }
我们演示了元素移除方法。removeWhere 允许根据条件过滤元素,而 clear 则清空整个集合。
$ dart main.dart Original: {apple, banana, orange, kiwi} After remove: {apple, orange, kiwi} After removeWhere: {apple, kiwi} After clear: {}
自定义对象的 HashSet
在 HashSet 中使用自定义对象时,我们必须正确实现 hashCode 和 ==。这可确保唯一性和查找的正确行为。
import 'dart:collection'; class Book { final String title; final String author; Book(this.title, this.author); @override bool operator ==(Object other) => identical(this, other) || other is Book && title == other.title && author == other.author; @override int get hashCode => title.hashCode ^ author.hashCode; } void main() { var library = HashSet<Book>(); var book1 = Book('Dart in Depth', 'John Doe'); var book2 = Book('Flutter Basics', 'Jane Smith'); var book3 = Book('Dart in Depth', 'John Doe'); // Same as book1 library.add(book1); library.add(book2); library.add(book3); print('Library size: ${library.length}'); print('book1 and book3 same: ${library.contains(book1) == library.contains(book3)}'); }
Book 类实现了 == 和 hashCode 以确保逻辑相等。book1 和 book3 被视为相同,因此只添加一个到集合中。
$ dart main.dart Library size: 2 book1 and book3 same: true
最佳实践
- 元素不变性:为稳定的哈希使用不可变对象。
- 正确的哈希:覆盖 == 时务必覆盖 hashCode。
- 空安全:考虑使用非可空类型以提高清晰度。
- 性能:HashSet 在 contains 检查方面表现出色 (O(1))。
- 顺序:不要依赖迭代顺序的稳定性。
来源
本教程介绍了 Dart 的 HashSet,并通过实际示例演示了其无序唯一集合的关键特性和用法模式。
作者
列出 所有 Dart 教程。