Vec :: dedup не работает - как мне дедуплицировать вектор строк?

Я проанализировал файл, разбил строку по строкам и хочу оставить только уникальные элементы в каждом векторе. Я ожидаю, что 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

Как удалить дубликаты?


person Дмитрий Рыбин    schedule 04.12.2017    source источник
comment
В документации указано, что дедупликация удаляет только последовательные дубликаты. Может сначала сортировать? doc.rust-lang.org/std/vec/struct.Vec. html   -  person lwi    schedule 04.12.2017


Ответы (2)


Как указано в документации, Vec#dedup удаляет только < сильные> последовательные элементы из вектора (это намного дешевле полной дедупликации). Было бы нормально работать, например, если бы вектор был vec!["a", "a", "b"].

Конечно, есть несколько потенциальных решений.

Чтобы получить вектор со всеми удаленными дубликатами с сохранением исходного порядка элементов, ящик itertools предоставляет _ 4_ адаптер.

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);
person E_net4 the curator    schedule 04.12.2017

Другой ответ указывает на то, что 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 требуется дополнительная память.

person ljedrz    schedule 05.12.2017
comment
В некотором смысле это должна быть встроенная форма адаптера unique. - person E_net4 the curator; 05.12.2017