How do I test for the equality of two unordered lists?
If you know that there can never be duplicates, you can use a set (HashSet
or BTreeSet
, depending on your types):
use std::{collections::HashSet, hash::Hash};
fn my_eq<T>(a: &[T], b: &[T]) -> bool
where
T: Eq + Hash,
{
let a: HashSet<_> = a.iter().collect();
let b: HashSet<_> = b.iter().collect();
a == b
}
fn main() {
assert!(my_eq(
&["foo", "bar", "baz", "beh"],
&["beh", "foo", "baz", "bar"]
));
assert!(!my_eq(
&["beh", "foo", "baz", "bar"],
&["beh", "foo", "baz", "baz"]
));
}
If you need to handle duplicates, you'll want to count the number of values too:
use std::{collections::HashMap, hash::Hash};
fn my_eq<T>(a: &[T], b: &[T]) -> bool
where
T: Eq + Hash,
{
fn count<T>(items: &[T]) -> HashMap<&T, usize>
where
T: Eq + Hash,
{
let mut cnt = HashMap::new();
for i in items {
*cnt.entry(i).or_insert(0) += 1
}
cnt
}
count(a) == count(b)
}
fn main() {
assert!(my_eq(
&["foo", "foo", "baz", "beh"],
&["beh", "foo", "baz", "foo"]
));
assert!(!my_eq(
&["foo", "foo", "baz", "beh"],
&["beh", "foo", "baz"]
));
}
If you want to be super fancy, you can create a newtype that adds this type of equality directly:
use std::{collections::HashMap, hash::Hash};
#[derive(Debug, Copy, Clone)]
struct CustomEq<'a, T: 'a>(&'a [T]);
impl<'a, T> CustomEq<'a, T>
where
T: Eq + Hash,
{
fn count(&self) -> HashMap<&T, usize> {
let mut cnt = HashMap::new();
for i in self.0 {
*cnt.entry(i).or_insert(0) += 1
}
cnt
}
}
impl<'a, T> PartialEq for CustomEq<'a, T>
where
T: Eq + Hash,
{
fn eq(&self, other: &Self) -> bool {
self.count() == other.count()
}
}
fn main() {
assert_eq!(
CustomEq(&["foo", "bar", "baz", "beh"]),
CustomEq(&["beh", "foo", "baz", "bar"])
);
assert_ne!(
CustomEq(&["beh", "foo", "baz", "bar"]),
CustomEq(&["beh", "foo", "baz", "baz"])
);
}