如何在保留订单的同时删除列表中的重复元素?

Ger*_*ero 6 collections list dart

我刚看到Seth Ladd的短片Collections.

Set只有唯一的元素(没有排序),但有时我需要一个有序列表,我想删除所有重复项(第二次出现一个元素,例如String应该从列表中删除)

原始输入到列表:A, B, C, B, D, A 应该导致A, B, C, D.我需要保留订单.结果就好B, A, D, C不会帮助我.

atr*_*eon 9

使用toSet然后toList

  var ids2 = ["A", "B", "C", "B", "D", "A"];
  var result = ids2.toSet().toList();

[A, B, C, D]
Run Code Online (Sandbox Code Playgroud)


Jus*_*ani 2

自己实现相当容易:

Iterable distinct(Iterable i) {
  var set = new Set();
  return i.where((e) {
    var isNew = !set.contains(e);
    set.add(e);
    return isNew;
  });
Run Code Online (Sandbox Code Playgroud)

Set.add()如果返回一个 bool 来指示集合是否被修改,那就更好了:

Iterable distinct(Iterable i) {
  var set = new Set();
  return i.where((e) => set.add(e));
}
Run Code Online (Sandbox Code Playgroud)

当然,您可以提交功能请求错误。

编辑:正如 Florian 指出的那样,上述解决方案仅在返回的内容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;
}
Run Code Online (Sandbox Code Playgroud)

是的,这要长得多,但它可以正确地处理多次使用的有限Iterable和一次性的无限Iterable。无限可迭代用例很容易出现内存问题,这是不将其包含在核心库中并迫使开发人员就他们到底需要什么做出一些决定的一个论点。