我刚看到a short video from Seth Ladd on Collections
。
Set只有唯一的元素(没有排序),但有时我需要一个有序列表,我想删除所有重复项(第二次出现一个元素,例如String应该从列表中删除)
列表的原始输入:A, B, C, B, D, A
应该会生成A, B, C, D
。我需要保留订单。像B, A, D, C
这样的结果对我没用。
答案 0 :(得分:3)
自行实施相当容易:
Iterable distinct(Iterable i) {
var set = new Set();
return i.where((e) {
var isNew = !set.contains(e);
set.add(e);
return isNew;
});
如果Set.add()
返回一个指示该集是否被修改的bool,那就更好了:
Iterable distinct(Iterable i) {
var set = new Set();
return i.where((e) => set.add(e));
}
您当然可以提交功能请求错误。
编辑:正如Florian所指出的,只有返回的Iterable
仅使用一次,上述解决方案才有效。后续使用将返回没有元素的Iterator
,因为在第一次使用时已经看到了偶数元素。
要解决此问题,我们需要为返回的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
和一次使用无限Iterable
s。无限可迭代的用例很容易出现内存问题,这是一个不在核心库中包含它的论据,并迫使开发人员对他们究竟需要什么做出一些决定。
答案 1 :(得分:3)
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.
}
答案 2 :(得分:3)
使用toSet
,然后使用toList
var ids2 = ["A", "B", "C", "B", "D", "A"];
var result = ids2.toSet().toList();
[A, B, C, D]
答案 3 :(得分:0)
使用泛型和生成器,您可以创建一个适用于任何类型的可迭代对象的函数
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()
的使用