我刚刚看到a short video from Seth Ladd on Collections
。
一个Set只有唯一的元素(不排序),但是有时候我需要一个有序列表,并且我想删除所有重复项(元素的第二次出现例如String应该从列表中删除)
原始输入到列表:A, B, C, B, D, A
应该产生A, B, C, D
。我需要保持秩序。像B, A, D, C
这样的结果对我没有帮助。
最佳答案
自己实现很容易:
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));
}
您当然可以提出功能请求错误。
编辑:正如弗洛里安指出,上述解决方案仅在返回的
Iterable
仅使用一次的情况下才有效。后续使用将返回不包含任何元素的Iterator
,因为在第一次使用时就已经看到了element。为了解决这个问题,我们需要为从返回的
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
一起正常工作。无限的可迭代用例很容易会遇到内存问题,这是一个论点,即不将其包含在核心库中,并迫使开发人员就他们真正需要什么做出一些决定。关于list - 如何在保留顺序的同时删除列表中的重复元素?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14665923/