Изучение операций с HashSet в Rust

Beginner

This tutorial is from open-source community. Access the source code

Введение

В этом лабе мы исследуем функциональность структуры данных HashSet в Rust, которая гарантирует уникальные элементы и может выполнять операции, такие как объединение, разность, пересечение и симметрическая разность для множеств.

Примечание: Если в лабе не указано имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать main.rs, скомпилировать и запустить его с помощью rustc main.rs &&./main.

HashSet

Рассмотрите HashSet как HashMap, где нас интересуют только ключи (на самом деле HashSet<T> - это просто обертка вокруг HashMap<T, ()>).

"Для чего это?" - вы задаете вопрос. "Я мог бы просто хранить ключи в Vec".

Уникальная особенность HashSet заключается в том, что гарантируется отсутствие дублирующихся элементов. Именно это контракт, который выполняет любая коллекция множества. HashSet - это всего лишь одна реализация. (см. также: BTreeSet)

Если вы вставите значение, которое уже присутствует в HashSet (то есть новое значение равно существующему и у них одинаковая хэш-сумма), то новое значение заменит старое.

Это очень полезно, когда вы никогда не хотите иметь более одного экземпляра чего-либо, или когда хотите знать, есть ли у вас уже что-то.

Но множества могут делать гораздо больше.

У множеств есть 4 основных операции (все следующие вызовы возвращают итератор):

  • union: получить все уникальные элементы обоих множеств.

  • difference: получить все элементы, которые находятся в первом множестве, но не во втором.

  • intersection: получить все элементы, которые находятся только в обоих множествах.

  • symmetric_difference: получить все элементы, которые находятся в одном множестве или в другом, но не в обоих одновременно.

Попробуйте все эти операции в следующем примере:

use std::collections::HashSet;

fn main() {
    let mut a: HashSet<i32> = vec![1i32, 2, 3].into_iter().collect();
    let mut b: HashSet<i32> = vec![2i32, 3, 4].into_iter().collect();

    assert!(a.insert(4));
    assert!(a.contains(&4));

    // `HashSet::insert()` возвращает false, если
    // уже было такое значение.
    assert!(b.insert(4), "Value 4 is already in set B!");
    // FIXME ^ Comment out this line

    b.insert(5);

    // Если тип элементов коллекции реализует `Debug`,
    // то коллекция реализует `Debug`.
    // Обычно она выводит свои элементы в формате `[elem1, elem2,...]`
    println!("A: {:?}", a);
    println!("B: {:?}", b);

    // Выведет [1, 2, 3, 4, 5] в произвольном порядке
    println!("Union: {:?}", a.union(&b).collect::<Vec<&i32>>());

    // Это должно вывести [1]
    println!("Difference: {:?}", a.difference(&b).collect::<Vec<&i32>>());

    // Выведет [2, 3, 4] в произвольном порядке.
    println!("Intersection: {:?}", a.intersection(&b).collect::<Vec<&i32>>());

    // Выведет [1, 5]
    println!("Symmetric Difference: {:?}",
             a.symmetric_difference(&b).collect::<Vec<&i32>>());
}

(Примеры адаптированы из документации.)

Резюме

Поздравляем! Вы завершили лабу по HashSet. Вы можете практиковаться в более многих лабах в LabEx, чтобы улучшить свои навыки.