ZetCode

Dart LinkedHashSet

最后修改于 2025 年 4 月 4 日

在 Dart 中,LinkedHashSet 是一个有序集合实现,它维护插入顺序。它通过确保唯一性并保留顺序来结合 Set 和 List 的属性。

LinkedHashSet 实现 Set 接口,并使用带有链表的哈希表。元素必须具有一致的 Object.==Object.hashCode 实现。

创建 LinkedHashSet

创建 LinkedHashSet 的最简单方法是使用构造函数。

main.dart
import 'dart:collection';

void main() {
  var colors = LinkedHashSet<String>();
  colors.add('red');
  colors.add('green');
  colors.add('blue');
  colors.add('red'); // Duplicate ignored

  print(colors);
}

我们创建一个颜色 LinkedHashSet。泛型类型指定 String 元素。我们使用 add() 添加元素,重复的元素会自动被忽略。

$ dart main.dart
{red, green, blue}

从 Iterable 创建 LinkedHashSet

我们可以使用 LinkedHashSet.from 从现有的 Iterable 创建 LinkedHashSet。

main.dart
import 'dart:collection';

void main() {
  var numbers = [3, 1, 4, 1, 5, 9, 2, 6];
  var uniqueNumbers = LinkedHashSet<int>.from(numbers);

  print('Original: $numbers');
  print('Unique ordered: $uniqueNumbers');
}

这会从一个包含重复项的列表中创建一个 LinkedHashSet。结果集按照首次出现顺序包含唯一的元素。

$ dart main.dart
Original: [3, 1, 4, 1, 5, 9, 2, 6]
Unique ordered: {3, 1, 4, 5, 9, 2, 6}

检查内容

LinkedHashSet 提供了检查元素和集合属性的方法。

main.dart
import 'dart:collection';

void main() {
  var vowels = LinkedHashSet<String>.from(['a', 'e', 'i', 'o', 'u']);

  print(vowels.contains('e')); // true
  print(vowels.contains('x')); // false
  print(vowels.first);        // a
  print(vowels.last);         // u
  print(vowels.length);       // 5
}

我们检查 LinkedHashSet 的各种属性。first 和 last 属性反映的是插入顺序,而不是字母顺序。

$ dart main.dart
true
false
a
u
5

集合操作

LinkedHashSet 支持标准的集合操作,如 union、intersection 和 difference。

main.dart
import 'dart:collection';

void main() {
  var setA = LinkedHashSet<int>.from([1, 2, 3, 4]);
  var setB = LinkedHashSet<int>.from([3, 4, 5, 6]);

  print('Union: ${setA.union(setB)}');
  print('Intersection: ${setA.intersection(setB)}');
  print('Difference: ${setA.difference(setB)}');
}

这些操作返回新的集合。union 合并两个集合中的元素,intersection 查找共同元素,difference 显示 setA 中不在 setB 中的元素。

$ dart main.dart
Union: {1, 2, 3, 4, 5, 6}
Intersection: {3, 4}
Difference: {1, 2}

遍历 LinkedHashSet

我们可以一边遍历 LinkedHashSet 元素,一边保持插入顺序。

main.dart
import 'dart:collection';

void main() {
  var planets = LinkedHashSet<String>.from([
    'Mercury', 'Venus', 'Earth', 'Mars',
    'Jupiter', 'Saturn', 'Uranus', 'Neptune'
  ]);

  print('Forward order:');
  for (var planet in planets) {
    print(planet);
  }

  print('\nReversed order:');
  for (var planet in planets.toList().reversed) {
    print(planet);
  }
}

这演示了正向和反向的遍历。反向遍历需要先转换为列表,因为集合没有反向功能。

$ dart main.dart
Forward order:
Mercury
Venus
Earth
Mars
Jupiter
Saturn
Uranus
Neptune

Reversed order:
Neptune
Uranus
Saturn
Jupiter
Mars
Earth
Venus
Mercury

移除元素

LinkedHashSet 提供了在保持顺序的同时删除元素的方法。

main.dart
import 'dart:collection';

void main() {
  var letters = LinkedHashSet<String>.from([
    'A', 'B', 'C', 'D', 'E', 'F', 'G'
  ]);

  print('Original: $letters');

  letters.remove('C');
  print('After remove: $letters');

  letters.removeWhere((letter) => letter.codeUnitAt(0) % 2 == 0);
  print('After removeWhere: $letters');

  letters.clear();
  print('After clear: $letters');
}

我们演示了三种删除方法。removeWhere 根据字符码进行过滤,删除 ASCII 值是偶数的字母。

$ dart main.dart
Original: {A, B, C, D, E, F, G}
After remove: {A, B, D, E, F, G}
After removeWhere: {A, D, F}
After clear: {}

带自定义对象的 LinkedHashSet

使用自定义对象时,我们必须正确实现 hashCode 和 ==。

main.dart
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;

  @override
  String toString() => '$title by $author';
}

void main() {
  var library = LinkedHashSet<Book>();
  var book1 = Book('1984', 'George Orwell');
  var book2 = Book('Brave New World', 'Aldous Huxley');
  var book3 = Book('1984', 'George Orwell'); // Same as book1

  library.add(book1);
  library.add(book2);
  library.add(book3);

  print(library);
  print('book1 and book3 same: ${library.contains(book3)}');
}

Book 类实现了 == 和 hashCode 来确保逻辑相等性。尽管 book1 和 book3 是不同的对象实例,但它们被认为是相同的。

$ dart main.dart
{1984 by George Orwell, Brave New World by Aldous Huxley}
book1 and book3 same: true

最佳实践

来源

Dart LinkedHashSet 文档

本教程通过实际示例介绍了 Dart 的 LinkedHashSet,演示了其关键特性和用法模式。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。至今,我已撰写了超过 1,400 篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程