Rust 如何将两个哈希集相交,同时将公共值移动到一个新的哈希集? 使用std::collections::HashSet; 让mut a:HashSet=HashSet::new(); 让mut b:HashSet=HashSet::new(); 让mut c:HashSet=a.intersection(&b).collect(); //错误:“std::collections::HashSet”类型的集合无法从“%T”类型元素的迭代器生成`

Rust 如何将两个哈希集相交,同时将公共值移动到一个新的哈希集? 使用std::collections::HashSet; 让mut a:HashSet=HashSet::new(); 让mut b:HashSet=HashSet::new(); 让mut c:HashSet=a.intersection(&b).collect(); //错误:“std::collections::HashSet”类型的集合无法从“%T”类型元素的迭代器生成`,rust,Rust,我不再需要不相交的值。 如何在不复制或克隆的情况下将数据从集合a和b中窃取/移动到c?理想情况下,这将具有理论上最佳的时间复杂度:O(min(a,b))。编译器施加的别名规则要求您来回移动值。值可以从集合中排出,尽管是无条件的。但是,如果我们跟踪哪些值应该被移动,哪些值应该保留在一个新的集合中,我们可以将某些值发回。之后,允许我们从第二个集合中删除公共值 使用std::collections::HashSet; 使用std::hash::hash; ///将“a”和“b”中的公共值提取到一个新集

我不再需要不相交的值。
如何在不复制或克隆的情况下将数据从集合
a
b
中窃取/移动到
c
?理想情况下,这将具有理论上最佳的时间复杂度:O(min(a,b))。

编译器施加的别名规则要求您来回移动值。值可以从集合中排出,尽管是无条件的。但是,如果我们跟踪哪些值应该被移动,哪些值应该保留在一个新的集合中,我们可以将某些值发回。之后,允许我们从第二个集合中删除公共值

使用std::collections::HashSet;
使用std::hash::hash;
///将“a”和“b”中的公共值提取到一个新集合中。
fn就地交叉点(a:&mut HashSet,b:&mut HashSet)->HashSet
哪里
T:散列,
T:Eq,
{
设x:HashSet=a
.排水管()
.地图(v){
设相交=b.contains(&v);
(五、交叉点)
})
.收集();
让mut c=HashSet::new();
对于x中的(v,is_inter){
如果你是国际米兰{
c、 插入(v);
}否则{
a、 插入(v);
}
}
b、 保留(&v)!c.包含(&v));
C
}
使用:

use std::collections::HashSet;
let mut a: HashSet<T> = HashSet::new();
let mut b: HashSet<T> = HashSet::new();
let mut c: HashSet<T> = a.intersection(&b).collect();
// Error: a collection of type `std::collections::HashSet<T>` cannot be built from an iterator over elements of type `&T`
使用itertools::itertools;//for.sorted()
让mut a:HashSet=[1,2,3].iter().cloned().collect();
让mut b:HashSet=[4,2,3].iter().cloned().collect();
设c=原地交叉点(&mut a和&mut b);
将a:Vec=a.放入iter().sorted().collect();
设b:Vec=b.into_iter().sorted().collect();
让c:Vec=c.放入iter().sorted().collect();
断言!(&a,&[1]);
断言!(&b,&[4]);
断言!(&c,&[2,3]);

或者,如果您可以拥有集合本身的所有权,而不关心在其他集合中保留不相交的值,则可以执行以下操作:

use itertools::Itertools;  // for .sorted()

let mut a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
let mut b: HashSet<_> = [4, 2, 3].iter().cloned().collect();

let c = inplace_intersection(&mut a, &mut b);

let a: Vec<_> = a.into_iter().sorted().collect();
let b: Vec<_> = b.into_iter().sorted().collect();
let c: Vec<_> = c.into_iter().sorted().collect();
assert_eq!(&a, &[1]);
assert_eq!(&b, &[4]);
assert_eq!(&c, &[2, 3]);

使用std::hash::hash;
使用std::collections::HashSet;
fn交叉点(a:HashSet,b:&HashSet)->HashSet{
a、 放入iter().filter(| e | b.contains(e)).collect()
}
这会将a中包含在b中的元素收集到一个新的HashSet中

另一个解决方案,但此解决方案不涉及先排空然后重新填充第一个集合。依我看,它也稍微容易阅读

use std::hash::Hash;
use std::collections::HashSet;

fn intersection<T: Eq + Hash>(a: HashSet<T>, b: &HashSet<T>) -> HashSet<T> {
    a.into_iter().filter(|e| b.contains(e)).collect()
}
fn就地交叉点(a:&mut HashSet,b:&mut HashSet)->HashSet
哪里
T:散列,
T:Eq,
{
让mut c=HashSet::new();
对于a.iter()中的v{
如果让一些(找到)=b.取(v){
c、 插入(找到);
}
}
a、 保留(&v)!c.包含(&v));
C
}

写了这篇文章后,我意识到可以让它变得更简单:

fn inplace_intersection<T>(a: &mut HashSet<T>, b: &mut HashSet<T>) -> HashSet<T>
where
    T: Hash,
    T: Eq,
{
    let mut c = HashSet::new();
    
    for v in a.iter() {
        if let Some(found) = b.take(v) {
            c.insert(found);
        }
    }
    
    a.retain(|v| !c.contains(&v));

    c
}
fn就地交叉点(a:&mut HashSet,b:&mut HashSet)->HashSet
哪里
T:散列,
T:Eq,
{
设c:HashSet=a.iter().filter_-map(|v | b.take(v)).collect();
a、 保留(&v)!c.包含(&v));
C
}

如果你能澄清(1)是否
a
b
应该保留非相交的值,或者这不重要,以及(2)你的目标算法复杂度。我要指出,如果相交后
a
b
的状态无关紧要,那么
a保留(…)
这一步是不必要的,我们有一个最佳效率的单道单衬板。
fn inplace_intersection<T>(a: &mut HashSet<T>, b: &mut HashSet<T>) -> HashSet<T>
where
    T: Hash,
    T: Eq,
{
    let c: HashSet<T> = a.iter().filter_map(|v| b.take(v)).collect();
    
    a.retain(|v| !c.contains(&v));

    c
}