rust - 通过查找自身中的键来替换HashSet值

标签 rust hashset

我有一个map: HashSet<String, String>,想有条件地改变每个值。

我想在我正在变异的相同HashSet中查找新值。

我该怎么办而不会出现借阅检查器问题?

fn main() {
    let mut map = std::collections::HashMap::new();
    map.insert("alien".to_string(), "".to_string());
    map.insert("covid".to_string(), "virus".to_string());
    map.insert("mammal".to_string(), "animal".to_string());
    map.insert("cat".to_string(), "mammal".to_string());
    map.insert("lion".to_string(), "cat".to_string());

    println!("{:#?}", map);

    // Replace values by lookup in self
    loop {
        let mut done = true;
        for (key, val) in map {
            if let Some(new) = map.get(val) {
                if let Some(old) = map.insert(key.clone(), new.clone()) {
                    if &old != new {
                        done = false;
                    }
                }
            }
        }
        if done {
            break;
        }
    }

    let mut result = std::collections::HashMap::new();
    result.insert("alien".to_string(), "".to_string());
    result.insert("covid".to_string(), "virus".to_string());
    result.insert("mammal".to_string(), "animal".to_string());
    result.insert("cat".to_string(), "animal".to_string());
    result.insert("lion".to_string(), "animal".to_string());

    println!("{:#?}", result);

    assert_eq!(map, result);
}

Playground

最佳答案

花了很多时间之后,这就是我使用@Stargateur的建议得出的。

我使用第二个HashMap来存储您要查找的内容-map定义的树(或更具体地说,树的森林)中每个节点的根。为了防止完全遍历这些树,我检查是否已找到父级的根。如果是这样,则无需寻找根目录,只需使用它即可。否则,我遍历树,直到找到根或在reducedMap中已经找到根为止,并且在遍历时,我存储了我访问过的节点-我们将找到的根也将是它们的根。

找到根后,我将此根分配给所有访问的节点。

最后,我们将作为引用映射的reducedMap转换为结果映射,以克隆字符串

    // map of shortcuts to root, just references, no string copying
    let mut reducedMap = std::collections::HashMap::<&std::string::String, &std::string::String>::new();

    for (key, mut val) in map.iter() {
        let mut intermediateKeys = vec![]; // all intermediate keys as we go to root
        loop { 
            intermediateKeys.push(key); // remember the intermediate key to update it's shortcut too
            if let Some(shortcut) = reducedMap.get(val) { 
                val = shortcut; // if we know the shortcut, take it and leave 
                break;
            } 
            if let Some(parent) = map.get(val) {
                val = parent; // while not root, go deeper
            } else {
                break; // reached the root
            }
        }
        // insert or update shortcuts for all intermediate keys (root is in `val`)
        intermediateKeys.drain(..) // take items and clear the vector
            .for_each(|k| *reducedMap.entry(k).or_insert(val) = val);
    }

    map = reducedMap.iter()
        .map(|(k, v)| (k.to_string(), v.to_string()))
        .collect();  // move result back, now actually cloning strings

Playground

关于rust - 通过查找自身中的键来替换HashSet值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61989575/

相关文章:

rust - 为什么协程有 future ?

generics - 特征的泛型类型和泛型关联类型有什么区别?

java - 当我们检查任何 Set!=null 时输出

java - HPPC DoubleOpenHashSet Clear() 方法

java - 有没有更好的方法可以一次向集合中添加多个单词?

rust - 有没有办法不释放在条件分支中创建的临时变量,而只用堆栈框架销毁它们? [复制]

rust - "expected type ` ( )`"在匹配表达式中意味着什么?

for-loop - 如何修复这两个 for 循环以允许修改矢量内容?

java - hashSet 中的重复值

algorithm - 在 O(n) 相交中排序