Random 我能有效地从哈希集中随机取样吗?

Random 我能有效地从哈希集中随机取样吗?,random,rust,hashset,Random,Rust,Hashset,我有一个std::collections::HashSet,我想采样并删除一个统一的随机元素 目前,我正在做的是使用rand.gen_range对索引进行随机采样,然后迭代HashSet以获取该索引元素。然后删除所选元素。这是可行的,但效率不高。是否有一种有效的方法对元素进行随机采样 下面是我的代码的精简版本: use std::collections::HashSet; extern crate rand; use rand::thread_rng; use rand::Rng; let

我有一个
std::collections::HashSet
,我想采样并删除一个统一的随机元素

目前,我正在做的是使用
rand.gen_range
对索引进行随机采样,然后迭代
HashSet
以获取该索引元素。然后删除所选元素。这是可行的,但效率不高。是否有一种有效的方法对元素进行随机采样

下面是我的代码的精简版本:

use std::collections::HashSet;

extern crate rand;
use rand::thread_rng;
use rand::Rng;

let mut hash_set = HashSet::new();

// ... Fill up hash_set ...

let index = thread_rng().gen_range(0, hash_set.len());
let element = hash_set.iter().nth(index).unwrap().clone();
hash_set.remove(&element);

// ... Use element ...

唯一允许在恒定时间内均匀采样的数据结构是具有恒定时间索引访问的数据结构
HashSet
不提供索引,因此无法在固定时间内生成随机样本

我建议首先将哈希集转换为
Vec
,然后从向量中采样。要删除一个元素,只需将最后一个元素移到它的位置即可–向量中元素的顺序无论如何都是无关紧要的

如果您希望以随机顺序使用集合中的所有元素,还可以将向量洗牌一次,然后在其上迭代

以下是在恒定时间内从
Vec
中删除随机元素的示例实现:

use rand::{thread_rng, Rng};

pub trait RemoveRandom {
    type Item;

    fn remove_random<R: Rng>(&mut self, rng: &mut R) -> Option<Self::Item>;
}

impl<T> RemoveRandom for Vec<T> {
    type Item = T;

    fn remove_random<R: Rng>(&mut self, rng: &mut R) -> Option<Self::Item> {
        if self.len() == 0 {
            None
        } else {
            let index = rng.gen_range(0..self.len());
            Some(self.swap_remove(index))
        }
    }
}
使用rand:{thread\u rng,rng};
酒馆{
类型项目;
fn删除\u随机(&mut self,rng:&mut R)->选项;
}
用于Vec的impl-RemoveRandom{
类型项=T;
fn删除\u随机(&mut self,rng:&mut R)->选项{
如果self.len()==0{
没有一个
}否则{
let index=rng.gen_range(0..self.len());
一些(自交换\移除(索引))
}
}
}

()

考虑Sven Marnach的答案,我想使用向量,但我也需要恒定时间插入而不重复。然后我意识到我可以维护向量和集合,并确保它们在任何时候都有相同的元素。这将允许使用重复数据消除的固定时间插入和固定时间随机删除

以下是我最终的实现:

struct VecSet<T> {
    set: HashSet<T>,
    vec: Vec<T>,
}

impl<T> VecSet<T>
where
    T: Clone + Eq + std::hash::Hash,
{
    fn new() -> Self {
        Self {
            set: HashSet::new(),
            vec: Vec::new(),
        }
    }
    fn insert(&mut self, elem: T) {
        assert_eq!(self.set.len(), self.vec.len());
        let was_new = self.set.insert(elem.clone());
        if was_new {
            self.vec.push(elem);
        }
    }
    fn remove_random(&mut self) -> T {
        assert_eq!(self.set.len(), self.vec.len());
        let index = thread_rng().gen_range(0, self.vec.len());
        let elem = self.vec.swap_remove(index);
        let was_present = self.set.remove(&elem);
        assert!(was_present);
        elem
    }
    fn is_empty(&self) -> bool {
        assert_eq!(self.set.len(), self.vec.len());
        self.vec.is_empty()
    }
}
结构向量集{ set:HashSet, 维克:维克, } impl向量集 哪里 T:Clone+Eq+std::hash::hash, { fn new()->Self{ 自我{ set:HashSet::new(), vec:vec::new(), } } fn插入(&M-self,元素:T){ assert_eq!(self.set.len(),self.vec.len()); 让was_new=self.set.insert(elem.clone()); 如果你是新的{ 自矢量推力(elem); } } fn删除\u随机(&mut self)->T{ assert_eq!(self.set.len(),self.vec.len()); 让index=thread_rng().gen_range(0,self.vec.len()); 让elem=self.vec.swap\u移除(索引); let was_present=self.set.remove(&elem); 断言!(你在场); 元素 } fn为空(&self)->bool{ assert_eq!(self.set.len(),self.vec.len()); self.vec.is_为空() } }