我刚刚看到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的访问集。我们可以通过创建IterableIterator子类(例如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/

10-12 04:42