我刚刚看到了来自 Seth Ladd 的短视频Collections
。
一个集合只有唯一的元素(没有排序),但有时我需要一个有序列表,我想删除所有重复项(第二次出现的元素,例如字符串应该从列表中删除)
列表的原始输入:A, B, C, B, D, A
应该导致A, B, C, D
. 我需要保持秩序。像这样的结果B, A, D, C
对我没有帮助。
我刚刚看到了来自 Seth Ladd 的短视频Collections
。
一个集合只有唯一的元素(没有排序),但有时我需要一个有序列表,我想删除所有重复项(第二次出现的元素,例如字符串应该从列表中删除)
列表的原始输入:A, B, C, B, D, A
应该导致A, B, C, D
. 我需要保持秩序。像这样的结果B, A, D, C
对我没有帮助。
使用toSet
然后toList
var ids2 = ["A", "B", "C", "B", "D", "A"];
var result = ids2.toSet().toList();
[A, B, C, D]
Justin Fagnani 已经给出了一个很好的答案。这是另一个:
Iterable distinct(Iterable i) {
var map = new LinkedHashMap();
i.forEach((x) { map[x] = true; });
return map.keys; // map.keys.toList() would free the map for GC.
}
自己实现相当容易:
Iterable distinct(Iterable i) {
var set = new Set();
return i.where((e) {
var isNew = !set.contains(e);
set.add(e);
return isNew;
});
Set.add()
如果返回一个表明该集合是否被修改的布尔值会更好:
Iterable distinct(Iterable i) {
var set = new Set();
return i.where((e) => set.add(e));
}
您当然可以提交功能请求错误。
编辑:正如弗洛里安指出的那样,上述解决方案仅在返回Iterable
的仅使用一次时才有效。后续使用将返回Iterator
没有元素的 s,因为在第一次使用时已经看到了偶数元素。
为了解决这个问题,我们需要为Iterator
从返回的每个创建的对象保留一个访问集Iterable
,而不仅仅是为Iterable
. 我们可以通过使用/创建Iterable
子Iterator
类来做到这一点:WhereIterable
WhereIterator
Iterable distinct(Iterable i) => new DistinctIterable(i);
class DistinctIterable<E> extends Iterable<E> {
final Iterable<E> _iterable;
DistinctIterable(this._iterable);
Iterator<E> get iterator {
return new DistinctIterator<E>(_iterable.iterator);
}
}
class DistinctIterator<E> extends Iterator<E> {
final Iterator<E> _iterator;
final Set<E> _visited = new Set<E>();
DistinctIterator(this._iterator);
bool moveNext() {
while (_iterator.moveNext()) {
if (!_visited.contains(_iterator.current)) {
_visited.add(_iterator.current);
return true;
}
}
return false;
}
E get current => _iterator.current;
}
是的,这要长得多,但它可以与多次使用的有限Iterable
s 和一次使用的无限Iterable
s 一起正常工作。无限可迭代用例很容易出现内存问题,这是不将其包含在核心库中的一个论点,并迫使开发人员就他们到底需要什么做出一些决定。
使用泛型和生成器,您可以创建一个适用于任何类型的 Iterables 的函数
Iterable<T> distinct<T>(Iterable<T> elements) sync* {
final visited = <T>{};
for (final el in elements) {
if (visited.contains(el)) continue;
yield el;
visited.add(el);
}
}
的使用distinct(["A", "B", "C", "B", "D", "A"])
或者,如果您想将其包装到扩展中:
extension IterableDistinctExt<T> on Iterable<T> {
Iterable<T> distinct() sync* {
final visited = <T>{};
for (final el in this) {
if (visited.contains(el)) continue;
yield el;
visited.add(el);
}
}
}
的使用["A", "B", "C", "B", "D", "A"].distinct()