use std::{
collections::HashSet,
hash::Hash,
};
use std::collections::HashMap;
fn set_overlap<T: Hash + Eq>(aset: &HashSet<T>, bset: &HashSet<T>) -> bool {
for el in aset {
if bset.contains(el) {
return true;
}
}
false
}
#[derive(Debug)]
pub struct DisjointSubsets<T> {
pub disjoint_sets: HashMap<String, HashSet<T>>,
}
pub const SEPARATOR: &str = "@SEP@";
impl<T: Hash + Eq> DisjointSubsets<T> {
pub fn new() -> Self {
DisjointSubsets {
disjoint_sets: HashMap::new(),
}
}
pub fn add(&mut self, setname: String, aset: HashSet<T>) {
if self.disjoint_sets.contains_key(&setname) {
panic!("inserting into existing setname")
}
let mut candidates: Vec<String> = Vec::new();
for (name, the_set) in &self.disjoint_sets {
if set_overlap(&aset, the_set) {
candidates.push(name.clone());
}
}
let mut newset: HashSet<T> = HashSet::new();
let mut newname = String::new();
for c in candidates {
let mut s = self.disjoint_sets.remove(&c).unwrap(); for el in s.drain() {
newset.insert(el);
}
newname.push_str(&c);
newname.push_str(SEPARATOR);
}
for el in aset {
newset.insert(el);
}
newname.push_str(&setname);
self.disjoint_sets.insert(newname, newset);
}
pub fn get_disjoint_set_ids(&self) -> Vec<Vec<String>> {
let mut setlist: Vec<Vec<String>> = Vec::with_capacity(self.disjoint_sets.len());
for id_str in self.disjoint_sets.keys() {
let s: Vec<String> = id_str.split(SEPARATOR).map(|x| x.to_string()).collect();
setlist.push(s);
}
setlist
}
pub fn get_disjoint_set_ids_and_set(&self) -> Vec<(Vec<String>, &HashSet<T>)> {
let mut setlist: Vec<(Vec<String>, &HashSet<T>)> =
Vec::with_capacity(self.disjoint_sets.len());
for id_str in self.disjoint_sets.keys() {
let s: Vec<String> = id_str.split(SEPARATOR).map(|x| x.to_string()).collect();
let theset = self.disjoint_sets.get(id_str).unwrap();
setlist.push((s, theset));
}
setlist
}
}
#[cfg(test)]
mod test {
use super::*;
fn vec2set<T: Eq + Hash>(x: Vec<T>) -> HashSet<T> {
x.into_iter().collect::<HashSet<T>>()
}
use crate::disjoint::DisjointSubsets;
use std::collections::{HashMap, HashSet};
#[test]
fn test_get_disjoint_set_ids() {
let a = vec2set(vec!["A", "B", "C"]);
let b = vec2set(vec!["D", "E"]);
let c = vec2set(vec!["B", "D"]);
let mut ds = DisjointSubsets::new();
ds.add("set1".to_string(), a);
ds.add("set2".to_string(), b);
let disjoint_setids = ds.get_disjoint_set_ids();
assert_eq!(disjoint_setids.len(), 2);
ds.add("set3".to_string(), c);
println!("AAA {:?}", ds);
let disjoint_setids = ds.get_disjoint_set_ids();
assert_eq!(disjoint_setids.len(), 1);
assert_eq!(
vec2set(disjoint_setids[0].clone()),
vec2set(vec!["set1".to_string(), "set2".to_string(), "set3".to_string()])
);
}
#[test]
fn testing_disjoint() {
let a = vec2set(vec!["A", "B", "C"]);
let b = vec2set(vec!["D", "E"]);
let c = vec2set(vec!["B", "D"]);
let d = vec2set(vec!["Z"]);
let mut ds = DisjointSubsets::new();
ds.add("set1".to_string(), a);
ds.add("set2".to_string(), b);
let mut expected: HashMap<String, HashSet<&str>> = HashMap::new();
let set1 = vec2set(vec!["A", "B", "C"]);
expected.insert("set1".to_string(), set1);
let set2 = vec2set(vec!["D", "E"]);
expected.insert("set2".to_string(), set2);
assert_eq!(ds.disjoint_sets, expected);
ds.add("set3".to_string(), c);
assert_eq!(ds.disjoint_sets.len(), 1);
ds.add("set4".to_string(), d);
let mut expected: HashMap<String, HashSet<&str>> = HashMap::new();
let set1 = vec2set(vec!["A", "B", "C", "D", "E"]);
expected.insert("set1@SEP@set2@SEP@set3".to_string(), set1);
let set2 = vec2set(vec!["Z"]);
expected.insert("set4".to_string(), set2);
assert_eq!(ds.disjoint_sets, expected);
}
}