How to populate a vector with predefined capacity? [duplicate] - rust

This question already has answers here:
What's the difference between len() and capacity()?
(2 answers)
How to allocate space for a Vec<T> in Rust?
(3 answers)
How do I generate a vector of random numbers in a range?
(2 answers)
Closed 3 years ago.
I am trying to populate a vector after initialising it with with_capacity() as the number of elements is known prior to its creation and it seems more efficient with it.
The following code does NOT populate with random values AT ALL: println!("{}", v.len()); outputs zero.
use rand::Rng;
fn main() {
const NUMBER_OF_RANDOM_NUMBERS: usize = 10;
let mut v = Vec::with_capacity(NUMBER_OF_RANDOM_NUMBERS);
for i in &mut v {
*i += rand::thread_rng().gen_range(1, 2^32);
}
println!("{}", v.len());
}
My thinking is after let mut v = Vec::with_capacity(NUMBER_OF_RANDOM_NUMBERS) a brand new vector gets initialised with 10 zeros and then using rand::thread_rng().gen_range(1, 2^32) to insert, or should I say, add a random number to each zero.
Am I missing something here?

with_capacity does not initialize the values of the vector, it just allocates space for them. From the documentation:
It is important to note that although the returned vector has the
capacity specified, the vector will have a zero length. For an
explanation of the difference between length and capacity, see
Capacity and reallocation.
This means that when your loop code is executed, there are no items in the vector, and therefore it loops a total of zero times. Resulting in no change in the vector.

Related

How to convert range to slice in rust?

I want to create a slice of numbers within certain range in Rust. However, the following syntax does not seem to work, as the output is a slice of length 1, composed of a Range object.
let count = 10;
let slice = [0..count/2];
What's the proper way to create a slice in Rust from a range?
You cannot create a slice directly from a range (unless you know an upper bound to the number of elements at compile time, in which case you can use an array), you have to use Vec:
let vec = Vec::from_iter(0..count/2);
let slice = vec.as_slice();

How to assign to a slice range? [duplicate]

This question already has answers here:
How do you copy between arrays of different sizes in Rust?
(3 answers)
Closed 1 year ago.
I have a mutable slice, and I want to replace its prefix if it equals a certain slice.
I tried this:
let len = prefix.len();
if slice.starts_with(prefix) {
slice[.. len - 1] = subst;
}
Playground
However,
error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
--> src/main.rs:13:9
|
13 | slice[.. len - 1] = *subst;
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
(Let's forget about the other type error in the playground; in my code, I have proper slices instead of arrays.)
I understand this as saying "The slices might have different length, so you cannot do this".
However, how can I do this when I explicitly checked that the lengths are the same?
You should try split_at_mut(), something like this:
let len = prefix.len();
if slice.starts_with(prefix) {
let (left, _right) = slice.split_at_mut(len);
left.copy_from_slice(subst);
}
There is also explanation about this specific problem here: copy_from_slice()
Edit:
As Jmb stated in a comment, split_at_mut() is not needed:
let len = prefix.len();
if slice.starts_with(prefix) {
slice[..len].copy_from_slice(subst);
}

Rust - how to find n-th most frequent element in a collection

I can't imagine this hasn't been asked before, but I have searched everywhere and could not find the answer.
I have an iterable, which contains duplicate elements. I want to count number of times each element occurs in this iterable and return n-th most frequent one.
I have a working code which does exactly that, but I really doubt its the most optimal way to achieve this.
use std::collections::{BinaryHeap, HashMap};
// returns n-th most frequent element in collection
pub fn most_frequent<T: std::hash::Hash + std::cmp::Eq + std::cmp::Ord>(array: &[T], n: u32) -> &T {
// intialize empty hashmap
let mut map = HashMap::new();
// count occurence of each element in iterable and save as (value,count) in hashmap
for value in array {
// taken from https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry
// not exactly sure how this works
let counter = map.entry(value).or_insert(0);
*counter += 1;
}
// determine highest frequency of some element in the collection
let mut heap: BinaryHeap<_> = map.values().collect();
let mut max = heap.pop().unwrap();
// get n-th largest value
for _i in 1..n {
max = heap.pop().unwrap();
}
// find that element (get key from value in hashmap)
// taken from https://stackoverflow.com/questions/59401720/how-do-i-find-the-key-for-a-value-in-a-hashmap
map.iter()
.find_map(|(key, &val)| if val == *max { Some(key) } else { None })
.unwrap()
}
Are there any better ways or more optimal std methods to achieve what I want? Or maybe there are some community made crates that I could use.
Your implementation has a time complexity of Ω(n log n), where n is the length of the array. The optimal solution to this problem has a complexity of Ω(n log k) for retrieving the k-th most frequent element. The usual implementation of this optimal solution indeed involves a binary heap, but not in the way you used it.
Here's a suggested implementation of the common algorithm:
use std::cmp::{Eq, Ord, Reverse};
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
pub fn most_frequent<T>(array: &[T], k: usize) -> Vec<(usize, &T)>
where
T: Hash + Eq + Ord,
{
let mut map = HashMap::new();
for x in array {
*map.entry(x).or_default() += 1;
}
let mut heap = BinaryHeap::with_capacity(k + 1);
for (x, count) in map.into_iter() {
heap.push(Reverse((count, x)));
if heap.len() > k {
heap.pop();
}
}
heap.into_sorted_vec().into_iter().map(|r| r.0).collect()
}
(Playground)
I changed the prototype of the function to return a vector of the k most frequent elements together with their counts, since this is what you need to keep track of anyway. If you only want the k-th most frequent element, you can index the result with [k - 1][1].
The algorithm itself first builds a map of element counts the same way your code does – I just wrote it in a more concise form.
Next, we buid a BinaryHeap for the most frequent elements. After each iteration, this heap contains at most k elements, which are the most frequent ones seen so far. If there are more than k elements in the heap, we drop the least frequent element. Since we always drop the least frequent element seen so far, the heap always retains the k most frequent elements seen so far. We need to use the Reverse wrapper to get a min heap, as documented in the documentation of BinaryHeap.
Finally, we collect the results into a vector. The into_sorted_vec() function basically does this job for us, but we still want to unwrap the items from its Reverse wrapper – that wrapper is an implemenetation detail of our function and should not be returned to the caller.
(In Rust Nightly, we could also use the into_iter_sorted() method, saving one vector allocation.)
The code in this answer makes sure the heap is essentially limited to k elements, so an insertion to the heap has a complexity of Ω(log k). In your code, you push all elements from the array to the heap at once, without limiting the size of the heap, so you end up with a complexity of Ω(log n) for insertions. You essentially use the binary heap to sort a list of counts. Which works, but it's certainly neither the easiest nor the fastest way to achieve that, so there is little justification for going that route.

How can one struct own both a sequence and an iterator on the sequence? [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
How can I store a Chars iterator in the same struct as the String it is iterating on?
(2 answers)
Closed 3 years ago.
I am trying to construct a Defiler struct that owns a fixed sequence and an internal state describing current position within this sequence. The idea is that it can be iterated upon, but sometimes be reset to the beginning of the sequence.
I have picked an iterator as the internal state to represent the current value of the sequence. The idea is that it would be dropped and replaced by a fresh iterator when it's time to reset.
Here is my least fancy naive try so far:
use std::slice::IterMut;
struct Defiler<'a> {
// This sequence should not change during the whole
// lifetime of the struct, although I have not expressed it yet.
seq: Vec<u32>,
// Internal state pointing towards the next element to be
// yielded. It will be randomly replaced by a fresh one.
current: IterMut<'a, u32>,
// ...
}
impl<'a> Defiler<'a> {
fn new(mut seq: Vec<u32>) -> Self {
Defiler {
seq,
current: seq.iter_mut(), // move out of borrowed value, of course.
}
}
// Restart the iteration from scratch.
fn reset(&'a mut self) {
self.current = self.seq.iter_mut();
}
// ...
}
I understand why the above does not compile, and I am aware that I have not expressed many things I wish the compiler to be reassured about:
even though its inner values are mutable, seq shall not grow or shrink during the whole lifetime of Defiler.
current will only iterate on owned values in seq, ever.
=> no dangling iteration can be produced, I'm (quite) sure.
How could I write it?

How to swap non-copyable elements in a vector? [duplicate]

This question already has an answer here:
How to swap the elements of an array, slice, or Vec?
(1 answer)
Closed 5 years ago.
I would like to swap String elements of a vector
let mut v_sa: Vec<String> = vec![];
...
let temp_a = v_sa_ib[j];
v_sa_ib[j] = v_sa_ib[j+1];
v_sa_ib[j+1] = temp_a;
It works with integers but not with Strings. I also tried to create a second vector temp_b (same type of temp_a) and to populate it instead of swapping but i got always the same error: the type of this value must be known in this context.
How can I fix it?
You can use the swap() method of Vec to swap two elements directly:
v_sa_ib(j, j+1);
There is also a generic swap function called std::mem::swap but it is difficult to use here because obtaining two mutable references two different elements of the same Vec is quite involved.
The reason why it worked with integers is that integers implement the Copy trait, so Rust can automatically create new copies.

Resources