I'm doing something like this:
fn main() {
//[1, 0, 0, 0, 99]; // return [2, 0, 0, 0, 99]
//[2, 3, 0, 3, 99]; // return [2,3,0,6,99]
//[2, 4, 4, 5, 99, 0]; // return [2,4,4,5,99,9801]
//[1, 1, 1, 4, 99, 5, 6, 0, 99]; // return [30,1,1,4,2,5,6,0,99]
let map: Vec<(&mut [usize], &[usize])> = vec![(&mut [1, 0, 0, 0, 99], &[2, 0, 0, 0, 99])];
for (x, y) in map {
execute_program(x);
assert_eq!(x, y);
}
}
pub fn execute_program(vec: &mut [usize]) {
//do something inside vec
}
Here the playground
The problem is that I don't use the let on the first element in the tuple, that i want to borrow to execute_program:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:2:57
|
2 | let map: Vec<(&mut [usize], &[usize])> = vec![(&mut [1, 0, 0, 0, 99], &[2, 0, 0, 0, 99])];
| ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
3 |
4 | for (x, y) in map {
| --- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
But what I was doing was a refactoring exactly because I didn't want to do a let for every slice I want to test!
Is the let really needed?
Well, something has to own each of those arrays, because references can't own things. And the arrays are of different sizes, so the owner has to be a pointer. The most common array-like owning pointer is Vec:
let map: Vec<(Vec<usize>, &[usize])> = vec![
(vec![1, 0, 0, 0, 99], &[2, 0, 0, 0, 99]),
(vec![2, 3, 0, 3, 99], &[2, 3, 0, 6, 99]),
(vec![2, 4, 4, 5, 99, 0], &[2, 4, 4, 5, 99, 9801]),
(vec![1, 1, 1, 4, 99, 5, 6, 0, 99], &[30, 1, 1, 4, 2, 5, 6, 0, 99]),
];
for (mut x, y) in map {
execute_program(&mut x);
assert_eq!(x, y);
}
The arrays are therefore owned by map and borrowed when necessary, as loganfsmyth also suggested in the question comments.
You may be concerned about the performance cost of making unnecessary allocations. This is the cost of using a single let; since the arrays are not all the same size, if you want them on the stack there really isn't a way around declaring them with different lets. However, you could write a macro that removes the boilerplate.
Wait, why does it work for y?
You may wonder why I turned x into a vector, but left y as it is. The answer is that because y is a shared reference, those arrays are subject to static promotion, so that &[2, 0, 0, 0, 99] is actually of type &'static [usize; 5] which can be coerced to &'static [usize]. &mut references do not trigger static promotion because it is unsafe to mutate a static value without some kind of synchronization.
Related
I'd like to split and collect this strangely-shaped vector
let v = vec![
0, 1, 2, 3,
4, 5, 6, 7,
8, 9,
10, 11,
12, 13,
];
into these two matrices:
let v1 = vec![
vec![0, 1, 2, 3],
vec![4, 5, 6, 7],
];
let v2 = vec![
vec![8, 9],
vec![10, 11],
vec![12, 13],
];
(The elements are sequential (i.e. 1, 2, 3, ...) but this is just for example. Also, though the number of matrices are two here, this number is just for example; sometimes it should be three or more.)
Trivially it is possible (Rust Playground):
let mut v1: Vec<Vec<usize>> = vec![];
for i in 0..2 {
v1.push(v.iter().skip(i * 4).take(4).copied().collect());
}
let mut v2: Vec<Vec<usize>> = vec![];
for i in 0..3 {
v2.push(v.iter().skip(8 + i * 2).take(2).copied().collect());
}
But, is there a cleaner way? Here's the pseudo code I want:
let v1 = v.iter().every(4).take(2).collect();
let v2 = v.iter().skip(8).every(2).take(3).collect();
You can split the initial vector into two slices and iterate each of them separately (playground):
let (left, right) = v.split_at(8);
let v1 = left.chunks(4).map(|s| s.to_vec()).collect::<Vec<_>>();
let v2 = right.chunks(2).map(|s| s.to_vec()).collect::<Vec<_>>();
If an external crate is allowed, you can use Itertools::chunks:
v.iter().chunks(4).into_iter().take(2).map(|l| l.copied().collect_vec()).collect()
(Rust Playground)
I have a vector of some elements that I would like to iterate from some index and cycle around from the front again while only visiting each element a single time.
Ex. starting here at index 2,
[0, 1, 2, 3, 4, 5, 6]
^
I would like to have an iterator over the elements [2, 3, 4, 5, 6, 0, 1] (and avoid writing a loop everywhere I need to run through the vector this way).
The standard iteration with cycle() + skip() seemed to be a good start, but it of cause never ends.
Is there any idiomatic way with rusts standard iterators?
You can iterate over the two subslices, and use chain to concatenate them together into a single iterator:
let v = vec![0, 1, 2, 3, 4, 5, 6];
let start_index = 2;
for e in v[start_index..].iter().chain(v[..start_index].iter()) {
println!("{}", e);
}
The obvious fix for your cycle/skip combo is to add a take() to limit it:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().skip(start_pos).take(slice.len())
}
Another option is to just chain the two ranges, which even ends up a bit shorter:
fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
slice[start_pos..].iter().chain(&slice[..start_pos])
}
Both versions pass test such as:
let v = vec![0, 1, 2, 3, 4, 5, 6];
assert_eq!(cycle(&v, 2).copied().collect::<Vec<_>>(), vec![2, 3, 4, 5, 6, 0, 1]);
I have a vector and I want to sort it, where the first criterion is frequency. Second criterion is position in the vector. If two elements have the same number of occurrences, I want the most recently seen element to take advantage and go first. In the end, I want to remove duplicate elements from it.
For instance, if the input is this:
fn main() {
let history = vec![3, 2, 4, 6, 2, 4, 3, 3, 4, 5, 6, 3, 2, 4, 5, 5, 3];
}
The output should be:
3 4 5 2 6
How can I do this in Rust?
A straightforward method is to build hash maps for frequencies and positions of the elements:
use std::collections::HashMap;
fn frequency_map(nums: &[i32]) -> HashMap<i32, usize> {
let mut map = HashMap::new();
for &n in nums {
*map.entry(n).or_insert(0) += 1;
}
map
}
fn position_map(nums: &[i32]) -> HashMap<i32, usize> {
let mut map = HashMap::new();
for (pos, &n) in nums.iter().enumerate() {
map.insert(n, pos);
}
map
}
And then do an unstable sort by position followed by a stable sort by frequency:
fn custom_sort(nums: &mut Vec<i32>) {
let freq_map = frequency_map(nums);
let pos_map = position_map(nums);
nums.sort_unstable_by(|a, b| pos_map.get(b).unwrap().cmp(pos_map.get(a).unwrap()));
nums.dedup();
nums.sort_by(|a, b| freq_map.get(b).unwrap().cmp(freq_map.get(a).unwrap()));
}
Example:
use itertools::Itertools;
fn main() {
let mut history = vec![3, 2, 4, 6, 2, 4, 3, 3, 4, 5, 6, 3, 2, 4, 5, 5, 3];
custom_sort(&mut history);
println!("[{}]", history.iter().format(", "));
}
Output:
[3, 4, 5, 2, 6]
(playground)
I have a slice of bytes start = [30u8; 5] and middle = [40u8; 3] and a vector of byte slices:
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
I want to concatenate everything together, in such a way that I will obtain a single byte slice which looks as
[30, 30, 30, 30, 30, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
However, although I can concatenate start and middle when I try to append the vector elements it fails. I know that I am wrongly trying to iterate through the elements of the vector to concatenate, but I can't figure out how to do it correctly?
fn main() {
let start = [30u8; 5];
let middle = [40u8; 4];
let first = [1u8; 10];
let second = [2u8; 10];
let third = [3u8; 10];
let elements: Vec<[u8; 10]> = vec![first, second, third];
println!("{:?}", elements.iter());
for key in elements.iter() {
println!("{:?}", key.iter());
}
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().iter().cloned())
.collect();
println!("{:?}", alltogether);
}
This example can be copy-pasted into the Rust playground.
You possibly want this:
let alltogether: Vec<u8> = start
.iter()
.cloned()
.chain(middle.iter().cloned())
.chain(elements.iter().flatten().cloned())
.collect();
Note that there is also copied (instead of cloned) that can be used for Copyable types.
If the stuff in elements does not implement IntoIterator itself, you can use flat_map to specify how to convert one element to an iterator.
I am trying to check if two Matrix Market format files contain the same matrix. In my actual code, due to the use of multi-threading, there is no guarantee that I am inserting items into a TriMat in the same order before being serialized to disk. As a result, when I load the resulting files and compare them, they are not always the same. How can I compare two different .mtx files and ensure that they are the same, regardless of insertion order?
Example code:
extern crate sprs;
use sprs::io::{write_matrix_market, read_matrix_market};
use sprs::TriMat;
fn main() {
let mut mat = TriMat::new((4, 20));
let mut vals = Vec::new();
vals.push((0, 19, 1));
vals.push((1, 14, 1));
vals.push((1, 19, 1));
vals.push((2, 17, 2));
for (i, j, v) in vals {
mat.add_triplet(i, j, v)
}
let _ = write_matrix_market("a.mtx", &mat).unwrap();
let mut mat2 = TriMat::new((4, 20));
let mut vals2 = Vec::new();
vals2.push((0, 19, 1));
vals2.push((1, 14, 1));
vals2.push((2, 17, 2)); // different order
vals2.push((1, 19, 1));
for (i, j, v) in vals2 {
mat2.add_triplet(i, j, v)
}
let _ = write_matrix_market("b.mtx", &mat2).unwrap();
let seen_mat: TriMat<usize> = read_matrix_market("a.mtx").unwrap();
let expected_mat: TriMat<usize> = read_matrix_market("b.mtx").unwrap();
assert_eq!(seen_mat, expected_mat);
}
And the resulting error:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `TriMatBase { rows: 4, cols: 20, row_inds: [0, 1, 1, 2], col_inds: [19, 14, 19, 17], data: [1, 1, 1, 2] }`,
right: `TriMatBase { rows: 4, cols: 20, row_inds: [0, 1, 2, 1], col_inds: [19, 14, 17, 19], data: [1, 1, 2, 1] }`', src/main.rs:31:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
You can see that these two matrices are actually identical, but that the items have been inserted in different orders.
Turns out you can convert to CSR to get it to work:
let seen_mat: TriMat<usize> = read_matrix_market("a.mtx").unwrap();
let expected_mat: TriMat<usize> = read_matrix_market("b.mtx").unwrap();
let a = seen_mat.to_csr();
let b = expected_mat.to_csr();
assert_eq!(a, b);