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

时间:2013-02-02 20:02:23

标签: list collections dart

我刚看到a short video from Seth Ladd on Collections

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

列表的原始输入:A, B, C, B, D, A应该会生成A, B, C, D。我需要保留订单。像B, A, D, C这样的结果对我没用。

4 个答案:

答案 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一样的WhereIterableWhereIterator子类来实现这一目标:

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() 的使用