在rust中生成n个不同的随机数

qmb5sa22  于 2023-05-17  发布在  其他
关注(0)|答案(2)|浏览(175)

我正在试着测试一个程序,它检查括号的正确使用。要做到这一点,我想生成正确使用方括号的长字符串(为了测试不正确的使用,我可以很容易地交换单个字符或字符组)
我可以很容易地生成一个非括号字符的向量。然而,要正确放置括号,我需要n唯一索引。我不知道一种方法来有效地生成随机索引(在一个范围内的唯一随机数列表),所以我想要么一种方法来做到这一点,或一种方法将随机数转换为唯一的索引。
我能想到的两个最好的方法是:
1.生成所有索引0-N的向量,对其进行混洗,然后取第一个n
1.生成一个随机数,测试它是否在一个散列集中,如果不是,添加它,如果它是再生的,直到它不是。重复此操作,直到散列集包含n成员,然后将其转换为向量
第一种方法对于N = n + $\epsilon$是有效的,但是对于N >> n是非常低效的,而第二种方法对于N = n + $\epsilon$是非常低效的,但是对于N >> n是有效的。
注意事项:

  1. n是括号数N是字符数
    1.对于那些不熟悉符号$\epsilon$是一些小正数
vhmi4jdf

vhmi4jdf1#

你已经回答了自己的问题:)
我会和1号一起去。虽然epsilon分析很好,但在真实的世界中,还有很多事情要做。向量上的随机访问非常非常快,而散列和重新生成随机数可能很慢(尽管基准测试总是如此)。
但是,如果您没有生成大量的括号,那么性能差异可能可以忽略不计。
对于第一个解决方案,您可以使用rand crate及其SliceRandom trait。执行以下操作:

use rand::seq::SliceRandom;

fn whatever() {
 let mut numbers: Vec<usize> = (0..N).iter().copied().collect();
 numbers.shuffle(&mut rand::thread_rng());
 let usable_numbers = numbers[0..n];
 // Tada
}

另一种解决方案

fn whatever() {
  let mut out_map = HashSet::new();
  while out_map.len() < n {
   out_map.insert(rand::thread_rng().gen::<usize>() % N);
  }

 let numbers = out_map.into_iter().collect::<Vec<_>>();

}
exdqitrt

exdqitrt2#

如果你真的想生成n不同的随机数,那么这是How to choose several random numbers from an interval?的副本。
然而,在您的情况下,与其首先生成一个非括号字符序列,然后插入括号,不如使用以下方法在单次传递中生成序列,这样可能更有效:

fn make_string (len: usize, mut n_brackets: usize) -> String {
    assert!(len >= 2*n_brackets);
    let mut result = String::with_capacity (len);
    let mut n_open = 0;
    let mut rng = rand::thread_rng();
    for i in 0..len {
        let sel = rng.gen_range (0 .. (len-i));
        if sel < n_open {
            result.push (')');
            n_open -= 1;
        } else if sel < n_open + 2*n_brackets {
            result.push ('(');
            n_open += 1;
            n_brackets -= 1;
        } else {
            result.push (rng.gen_range ('a' .. 'z'));
        }
    }
    result
}

Playground

相关问题