Simon Tran
Simon Tran

Reputation: 2100

How to get the same output when using the `difference` function of a HashSet?

I'm using HashSets to find the differences between 2 vectors

let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
let b = vec!["a".to_string(), "c".to_string(), "d".to_string()];

let a_set: HashSet<&String> = HashSet::from_iter(a.iter());
let b_set: HashSet<&String> = HashSet::from_iter(b.iter());

let missing_a = b_set.difference(&a_set).cloned().collect();
let missing_b = a_set.difference(&b_set).cloned().collect();

assert_eq!(missing_a, vec!["c".to_string(), "d".to_string()]);
assert_eq!(missing_b, vec!["f".to_string(), "e".to_string()]);

Currently, the order of missing_a and missing_b is not the same each time it is run, so the test can fail.

How can I make sure that HashSet::difference returns the same output every time?

Upvotes: 1

Views: 320

Answers (2)

Simon Tran
Simon Tran

Reputation: 2100

Thanks to @PitaJ, I decided to use a BTreeSet:

let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
let b = vec!["a".to_string(), "c".to_string(), "d".to_string()];

let a_set: BTreeSet<&String> = BTreeSet::from_iter(a.iter());
let b_set: BTreeSet<&String> = BTreeSet::from_iter(b.iter());

let missing_a = b_set.difference(&a_set).cloned().collect();
let missing_b = a_set.difference(&b_set).cloned().collect();

assert_eq!(missing_a, vec!["c".to_string(), "d".to_string()]);
assert_eq!(missing_b, vec!["f".to_string(), "e".to_string()]);

Upvotes: 1

cdhowie
cdhowie

Reputation: 169256

Hash-based containers typically do not have deterministic ordering. From the documentation for HashSet::iter():

An iterator visiting all elements in arbitrary order.

Just collect the results into a container type that does not take order into account when comparing container values for equality -- such as HashSet:

fn main() {
    let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
    let b = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];

    let a_set: HashSet<&String> = HashSet::from_iter(a.iter());
    let b_set: HashSet<&String> = HashSet::from_iter(b.iter());

    let missing_a = b_set.difference(&a_set).cloned().collect::<HashSet<_>>();
    let missing_b = a_set.difference(&b_set).cloned().collect::<HashSet<_>>();

    assert_eq!(missing_a, HashSet::from_iter([&"c".to_string(), &"d".to_string()]));
    assert_eq!(missing_b, HashSet::from_iter([&"f".to_string(), &"e".to_string()]));
}

(Playground)

Upvotes: 3

Related Questions