Vec :: dedup不起作用 - 如何重复删除字符串向量?

时间:2017-12-04 15:25:05

标签: string vector rust

我已经解析了一个文件,按行拆分字符串,并希望在每个向量中只留下唯一的元素。我希望vec.dedup()能够像这样工作:

let mut vec = vec!["a", "b", "a"];
vec.dedup();
assert_eq!(vec, ["a", "b"]);

但它失败了:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `["a", "b", "a"]`,
 right: `["a", "b"]`', src/main.rs:4:4

如何删除重复项?

2 个答案:

答案 0 :(得分:10)

如上所述,Vec#dedup仅从向量中删除连续元素(它比完整重复数据删除便宜得多)。例如,如果向量为vec!["a", "a", "b"],它将正常工作。

当然,有多种潜在的解决方案。

为了获得在保留元素原始顺序的同时删除所有重复项的向量,itertools包提供了unique适配器。

use itertools::Itertools;

let v = vec!["b", "a", "b"];
let v: Vec<_> = v.into_iter().unique().collect();
assert_eq!(v, ["b", "a"]);

如果元素顺序不重要,您可以先对元素进行排序,然后调用重复数据删除。

let mut v = vec!["a", "b", "a"];
v.sort_unstable();
v.dedup();
assert_eq!(v, ["a", "b"]);

如果快速元素查找很重要,您也可以考虑使用集合类型,例如HashSet

let v: HashSet<_> = ["a", "b", "a"].iter().cloned().collect();
let v2: HashSet<_> = ["b", "a"].iter().cloned().collect();
assert_eq!(v, v2);

答案 1 :(得分:2)

另一个答案指出,对于没有重复的集合,HashSet是更好的选择,我同意这一点。这显示了如何使用Vec的属性直接对HashMap进行重复数据删除,而不首先对Vec进行排序以使用std::vec::Vec::dedup

use std::hash::Hash;
use std::collections::HashSet;

fn dedup<T: Eq + Hash + Copy>(v: &mut Vec<T>) { // note the Copy constraint
    let mut uniques = HashSet::new();
    v.retain(|e| uniques.insert(*e));
}

fn main() {
    let mut v = vec!["a", "b", "a"];
    dedup(&mut v);

    assert_eq!(&v, &vec!["a", "b"]);
}

这是一个快速(O(n))解决方案,但创建HashSet需要一些额外的内存。