Consider the following code:
fn main() {
let mut rows: Vec<Vec<u32>> = Vec::from([
Vec::from([1, 2, 3]),
Vec::from([4, 5, 6]),
Vec::from([7, 8, 9]),
]);
let res: Vec<Vec<u32>> = rows.iter().map(|arr| arr.reverse()).collect();
}
I have an vector of vectors of integers, and I want to reverse each of the arrays present in rows.
Using this code gives a type annotation problem, where map function considers arr to be of the type &Vec<u32> while .reverse() expects it to be of the type Vec<u32>.
How can I overcome it?
1. If you don't need the original rows anymore
You could use into_iter:
fn main() {
let rows: Vec<Vec<u32>> = Vec::from([
Vec::from([1, 2, 3]),
Vec::from([4, 5, 6]),
Vec::from([7, 8, 9]),
]);
let res: Vec<Vec<u32>> = rows.into_iter().map(|mut arr| {arr.reverse(); arr}).collect();
}
or do it inplace using iter_mut:
fn main() {
let mut rows: Vec<Vec<u32>> = Vec::from([
Vec::from([1, 2, 3]),
Vec::from([4, 5, 6]),
Vec::from([7, 8, 9]),
]);
rows.iter_mut().for_each(|mut arr| arr.reverse());
}
2. If you do need the rows afterwards:
fn main() {
let rows: Vec<Vec<u32>> = Vec::from([
Vec::from([1, 2, 3]),
Vec::from([4, 5, 6]),
Vec::from([7, 8, 9]),
]);
let res: Vec<Vec<u32>> = rows.iter().map(|arr| {
let mut arr = arr.clone();
arr.reverse();
arr
}).collect();
}
Related
Rust does not allow borrowing multiple mutable references. I understand that. But I can not find any elegant way to implement a few algorithms. Below is a simplified version of one such algorithm. The Ladder struct hands out slices of ever increasing sequence of numbers, such as, [0], [0, 1], [0, 1, 2] and so on.
struct Ladder {
position: usize,
data: [u8; 10],
}
impl Ladder {
fn get_next(&mut self) -> &[u8] {
self.position += 1;
&(self.data[0..self.position])
}
fn new() -> Ladder {
Ladder {
position: 0,
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}
I need to call get_next() a couple of times, collect the returned sequences and call a closure that will do something with those sequences.
fn test_ladder(consumer: impl Fn(&[&[u8]])) {
let mut l = Ladder::new();
let mut steps: [&[u8]; 3] = [&[]; 3];
steps[0] = l.get_next();
steps[1] = l.get_next();
steps[2] = l.get_next();
consumer(&steps);
}
fn main() {
test_ladder(|steps| {
for seq in steps {
println!("{:?}", *seq);
}
});
}
It is a non-allocating algorithm. I can not use std::Vec.
What is the idiomatic way to approach problems like this?
The problem here is that you can't keep references to something that you mutate, and .get_next() is allowed to mutate data. What you need to do is separate the data from the mutation. You can do that by only keeping a reference to the original data.
Creating a sequence of elements sounds a lot like an iterator, so here's an example:
struct LadderIter<'a> {
position: usize,
data: &'a [u8],
}
impl<'a> LadderIter<'a> {
fn new(data: &'a [u8]) -> LadderIter<'a> {
LadderIter { position: 0, data }
}
}
impl<'a> Iterator for LadderIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.position == self.data.len() {
None
} else {
self.position += 1;
Some(&self.data[0..self.position])
}
}
}
Which you can then use as an iterator:
for step in LadderIter::new(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) {
println!("{step:?}");
}
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Or in your specific use-case:
let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut ladder = LadderIter::new(&data);
let steps: [&[u8]; 3] = [
ladder.next().unwrap(),
ladder.next().unwrap(),
ladder.next().unwrap(),
];
Another approach is to use interior mutability. Since you are only modifying position, you can use the zero-cost Cell:
use std::cell::Cell;
struct Ladder {
position: Cell<usize>,
data: [u8; 10],
}
impl Ladder {
fn get_next(&self) -> &[u8] {
self.position.set(self.position.get() + 1);
&self.data[0..self.position.get()]
}
fn new() -> Ladder {
Ladder {
position: Cell::new(0),
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
}
I'm trying to improve the following method:
let output: Vec<i32> = stream::iter(vec![1, 2, 3])
.then(|val| {
future::ok::<_, ()>(vec![val * 10, val * 10 + 1])
})
.try_collect::<Vec<Vec<_>>>()
.await?
.into_iter()
.flatten() // How to flatten directly from the stream?
.collect();
assert_eq!(output, vec![10, 11, 20, 21, 30, 31]);
This method works but I think this could be improved because, as you can see, I need to collect two times in order to have the output I want.
This issue comes from the fact that I'm trying to flatten Results that contain a list. I tried to use try_flatten() however I absolutely can't make it work. Does anybody have an idea on how to achieve this?
I'm not sure how to use the future iterator adaptors, but you can accomplish the same thing like this:
use futures::{future, stream, StreamExt};
async fn f() -> Result<Vec<i32>, ()> {
let mut output = Vec::new();
let mut stream = stream::iter(vec![1, 2, 3])
.then(|val| future::ok::<_, ()>(vec![val * 10, val * 10 + 1]));
while let Some(items) = stream.next().await {
output.extend(items?);
}
assert_eq!(output, vec![10, 11, 20, 21, 30, 31]);
Ok(output)
}
#[tokio::main]
async fn main() {
println!("{:?}", f().await.unwrap());
}
just to let you know that I found the try_concat method in the TryStreamExt module that does exactly what I wanted.
let output: Vec<i32> = stream::iter(vec![1, 2, 3])
.then(|val| {
future::ok::<_, ()>(vec![val * 10, val * 10 + 1])
})
.try_concat()
.await?;
assert_eq!(output, vec![10, 11, 20, 21, 30, 31]);
I have to Vecs: vec_a and vec_b. Both the same size. I want to perform element-wise subtraction between the two vectors and save the answer in a third vector vec_c. For example:
vec_a = [1, 2, 3]
vec_b = [0, 2, -3]
vec_c = vec_a - vec_b = [1, 0, 6]
The solution I've come with is this function:
pub fn elementwise_subtraction(vec_a: Vec<i32>, vec_b: Vec<i32>) -> Vec<i32> {
let mut vec_c = Vec::new();
for i in 0..vec_a.len() {
vec_c.push(vec_a[i] - vec_b[i]);
}
vec_c
}
I feel like this is a bit verbose for a pretty simple operation. Is there a better/more idiomatic way to do this?
There is no such thing built in, you have to implement it yourself or use a third-party crate.
Anyway, you can continue to improve your code using functional programming:
pub fn elementwise_subtraction(vec_a: Vec<i32>, vec_b: Vec<i32>) -> Vec<i32> {
vec_a.into_iter().zip(vec_b).map(|(a, b)| a - b).collect()
}
let vec_a = vec![1, 2, 3];
let vec_b = vec![0, 2, -3];
let vec_c = elementwise_subtraction(vec_a, vec_b);
assert_eq!(vec_c, [1, 0, 6])
If you want to make it more generic (e.g. accepting both slices or Vec, any subtractable type):
use std::ops::Sub;
pub fn elementwise_subtraction<N, IA, IB, F>(a: IA, b: IB) -> F
where
N: Sub,
IA: IntoIterator<Item = N>,
IB: IntoIterator<Item = N>,
F: FromIterator<N> + FromIterator<<N as Sub>::Output>,
{
a.into_iter().zip(b).map(|(a, b)| a - b).collect()
}
let vec_a = [1, 2, 3];
let vec_b = [0, 2, -3];
let vec_c: Vec<_> = elementwise_subtraction(vec_a, vec_b);
assert_eq!(vec_c, [1, 0, 6])
Try it on playground
You'll need to use zip and map:
fn main() {
let vec_a = [1, 2, 3];
let vec_b = [0, 2, -3];
let vec_c: Vec<i32> = vec_a
.iter()
.zip(vec_b)
.map(|(elem_a, elem_b)| elem_a - elem_b)
.collect();
for elem_c in vec_c {
println!("{}", elem_c);
}
}
Your method is likely the most efficient way since it uses straight indexing, but an iterator method could look like this:
assert_eq!(
vec_a
.iter()
.zip(vec_b)
.map(|(a, b)| a - b)
.collect::<Vec<_>>(),
vec![1, 0, 6]
);
"Better" is always subjective, so if performance is your priority you should benchmark different methods; I've been surprised by results before.
code first:
use std::collections::HashMap;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {
vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
m
}),*
]
};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
I have above macro to generate a vec, contains several HashMap, in which these HashMap value is a vec as well,
{"A": [1, 2, 3]} => vec value length: 3,
{"B": [3, 4]} => vec value length: 2,
I wanna all the HashMap have the same length,
how to write in the macro to control this?
You can change the macro so that it creates a block (second set of {} encapsulating the macro definition) that you can set helper variables in and do a second pass over your vector, resizing anything that is smaller than the largest array.
In this case I've resized the arrays with the default value of the type to keep it simple. You may wish to wrap the data in Some().
This:
use std::cmp;
use std::collections::HashMap;
use std::default::Default;
macro_rules! arr{
([$($t:expr=>[$($c:expr),*]),*]) => {{
let mut max = 0;
let mut result = vec![
$({
let mut m = HashMap::new();
m.insert($t, vec![$($c),*]);
// Simply unwrap here as we know we inserted at this key above
max = cmp::max(max, m.get($t).unwrap().len());
m
}),*
];
for m in result.iter_mut() {
for v in m.values_mut() {
if v.len() < max {
v.resize_with(max, Default::default);
}
}
}
result
}};
}
fn main() {
let a = arr!([
"A"=>[1,2,3],
"B"=>[3,4]
]);
println!("{:?}", a);
//print: [{"A": [1, 2, 3]}, {"B": [3, 4]}]
}
Yields:
[{"A": [1, 2, 3]}, {"B": [3, 4, 0]}]
In trying to chain std::iter::Iterator::take_while calls together I'm losing the last values of each call.
Is there a way to chain calls together like this without skipping values?
Code Playground link:
use std::fmt;
#[derive(Clone)]
struct Point {
value: u8,
xe: u8,
xs: u8,
y: u8,
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
fn main() {
// All values following 5s within its x distance, partitioned by whether it is above or below.
// Sorted by xs (x start) (xe = x end)
#[rustfmt::skip]
let vec:Vec<Point> = vec![
Point { value: 4, xe: 1, xs: 1, y: 2 }, // 4
Point { value: 3, xe: 3, xs: 2, y: 3 }, // 3
Point { value: 5, xe: 7, xs: 4, y: 6 }, // ---- 5 -----
Point { value: 3, xe: 5, xs: 5, y: 4 }, // 3
Point { value: 6, xe: 6, xs: 6, y: 8 }, // 6
Point { value: 2, xe: 8, xs: 8, y: 3 }, // 2
Point { value: 8, xe: 10, xs: 9, y: 2 }, // 8
Point { value: 5, xe: 15, xs: 10, y: 7 }, // ---- 5 -----
Point { value: 2, xe: 12, xs: 11, y: 10 }, // 2
Point { value: 7, xe: 13, xs: 13, y: 9 }, // 7
Point { value: 4, xe: 14, xs: 14, y: 2 } // 4
];
let mut iter = vec.iter();
loop {
let c: Vec<_> = iter
.by_ref()
.take_while(|x| x.value != 5)
.cloned()
.collect();
println!("c: {:.?}", c);
if let Some(var) = iter.next() {
println!("var: {:.?}", var);
let (a, b): (Vec<_>, Vec<_>) = iter
.by_ref()
.take_while(|x| x.xe < var.xe)
.partition(|x| x.y > var.y);
println!("a: {:.?}", a);
println!("b: {:.?}", b);
} else {
break;
}
}
}
Output:
c: [4, 3]
var: 3
a: []
b: []
c: [2, 8]
var: 2
a: []
b: []
c: [4]
It should output:
c: [4, 3]
var: 5
a: [3]
b: [6]
c: [2, 8]
var: 5
a: [2, 7]
b: [4]
Using take_while with std::iter::Iterator::partition seemed a good way to make the code for this relatively clean.
In context the c, a and b values would be passed to functions whose results would be appended to a return value.
Using next_if() and from_fn():
use std::iter::from_fn;
// ...
let mut iter = vec.iter().peekable();
// ...
let c: Vec<_> = from_fn(|| iter.next_if(|x| x.value != 5))
.cloned()
.collect();
// ...
let (a, b): (Vec<_>, Vec<_>) = from_fn(|| iter.next_if(|x| x.xe < var.xe))
.partition(|x| x.y > var.y);
Using peeking_take_while() (better) or take_while_ref() from itertools, just replace the function.