1

*Note i'm using the 'rand' crate.

I'm new to rust and through some research and testing I was able to find two solutions to this:

#1: This on initializes an array and then populates it with random values:

type RandomArray = [usize; 900]; 

pub fn make_array() -> RandomArray {

    let mut rng = thread_rng();
    
    let mut arr: RandomArray = [0; 900];
        
    for i in 0..900 {
        //I need a range of random values!
        arr[i] = rng.gen_range(0..900)
    }

    arr
}

#2: This one initializes an array, it populates it with values from 0 to 900 and then shuffles it:

type RandomArray = [usize; 900]; 

pub fn make_shuffled_array() -> RandomArray  {
    let mut rng = thread_rng();
    
    let mut arr: RandomArray = [0; 900];
        
    for i in 0..900 {
        arr[i] = i;
    }

    arr.shuffle(&mut rng);

    arr
}

Through my testing, it seems like '#1' is slower but more consistent. But none of these actually initializes the array with the random range of numbers.

Both of these seem to be pretty fast and simple, however, I'm sure that there is an even faster way of doing this.

Tony
  • 266
  • 1
  • 11
  • BIG is relative. A heap-allocated array of hundreds of megabytes could be zero-allocated (which is ~free) and then initialized in chunks from a threadpool if your program already has one lying around. – the8472 Oct 22 '22 at 12:20

1 Answers1

2

When it comes to generating "random" data I don't know what exactly you need. To me #1 seems like it does what you describe. If you want to have random range bounds you can generate them first and only then use gen_range.

When it comes to the performance #1 should be faster, since it walks the whole array twice (once in the creation, and once in the initialization), but #2 walks it three times (creation, initialization and shuffling). You can't really do anything about the initialization part, but you can skip the "creation" part.

Rust requires that all data is initialized. Therefore you must specify what elements are in your array at the beginning, event though you will overwrite it on the next step. To opt-out from this you can use rust's special type MaybeUninit. I encourage you to read carefully it's documentation, since using it is very unsafe, but here you have a simple example of how you could use it.

use std::mem::{transmute, MaybeUninit};

fn get_random() -> usize {
    // chosen by fair dice roll.
    // https://xkcd.com/221/
    4
}

const N: usize = 900;

fn make_array() -> [usize; N] {
    // Unstable MaybeUninit::uninit_array
    let mut array: [MaybeUninit<usize>; N] =
        unsafe { MaybeUninit::<[MaybeUninit<usize>; N]>::uninit().assume_init() };

    for x in &mut array {
        x.write(get_random());
    }

    // Acts like unstable MaybeUninit::array_assume_init
    let array: [usize; N] = unsafe { transmute(array) };

    array
}
Aleksander Krauze
  • 3,115
  • 7
  • 18
  • 1
    [array::from_fn](https://doc.rust-lang.org/std/array/fn.from_fn.html) uses an uninitialized array under the hood so it may provide the same performance with more concise code. – the8472 Oct 22 '22 at 12:19