I would like to zip two vectors together, but what I get when calling the zip function is (&i32, &i32). I would like to get (i32, i32) - copy values from both vectors into a new vector.
let v1 = vec![1,2,3];
let v1 = vec![4,5,6];
// what I want
let zipped : Vec<(i32, i32)> = v1.iter().zip(v2.iter()).collect();
// what I actually get
let zipped : Vec<(&i32, &i32)> = v1.iter().zip(v2.iter()).collect();
Is it possible to force the zip function to copy the values?
zip() doesn't influence the values you're iterating over, it simply creates an iterator over tuples of the first and second iterator's values.
If you want to get owned values, you can use into_iter() on the Vecs. This will consume the vectors, so you can't use them anymore after the call. If you need to keep those vectors around, there's a copied() method that can be called on iterators over types that implement Copy, which is the case for i32. So you can get the same result while keeping the Vecs around by v1.iter().copied().zip(v2.iter().copied()).collect().
You can use cloned:
let zipped : Vec<(i32, i32)> = v1.iter().cloned().zip(v2.iter().cloned()).collect();
Playground
Related
I'm trying this, but doesn't work:
let map = HashMap::new();
map.insert(1, "aaa");
map.insert(2, "bbb");
let a = map.counts_by(|k, v| v.starts_with("a"));
What is the right way?
Anything that iterates over collections in Rust is going to factor through the Iterator API, and unlike in Java where iterators are often implicitly used, it's very common in Rust to explicitly ask for an iterator (with .iter()) and do some work directly on it in a functional style. In your case, there are three things we need to do here.
Get the values of the HashMap. This can be done with the values method, which returns an iterator.
Keep only the ones satisfying a particular predicate. This is a filter operation and will produce another iterator. Note that this does not yet iterate over the hash map; it merely produces another iterator capable of doing so later.
Count the matches, using count.
Putting it all together, we have
map.values().filter(|v| v.starts_with("a")).count()
You should filter an iterator of the HashMap, then count the elements of the iterator:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, "aaa");
map.insert(2, "bbb");
assert_eq!(
map.iter().filter(|(_k, v)| v.starts_with("a")).count(),
1
);
}
Notice that the map also has to be marked as mut in order to insert new elements, and the filter closure destructures into a tuple containing the key and the value, rather than accepting two separate parameters.
Suppose that I have the following code snippet:
fn foo(xs: &[i32]) {
xs.sort(); // doesn't work since not mut
// computation on xs
}
This function takes in an unsorted immutable slice but I need it to be sorted for computations later on in the function. I also cannot change the function signature. Is there a way to sort xs out of place or a way to convert xs into a mutable slice?
I've tried cloning and mapping but it seems that the problem is with the type of xs.
Since the data is immutable, you have to make a mutable copy of it first. You do not statically know the size of the slice parameter, so you need to use a Vec (instead of an array) to copy into. Then you can sort that Vec and use it normally in the rest of your function:
fn foo(xs: &[i32]) {
let mut xs = xs.to_vec();
xs.sort();
// computation on xs
}
I want to write a function in Rust that will return the vector composed of start integer, then all intermediate integers and then end integer. The assertion it should hold is this:
assert_eq!(intervals(0, 4, 1..4), vec![0, 1, 2, 3, 4]);
The hint is to use chain method for iterators. The function declaration is predefined, I implemented it in one way, which is the following code:
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
let mut a1 = vec![];
a1.push(start);
let inter: Vec<u32> = intermediate.into_iter().collect();
let mut iter : Vec<u32> = a1.iter().chain(inter.iter()).map(|x| *x).collect();
iter.push(end);
return iter;
}
But I am quite convinced this is not really optimal way to do this. I am sure I am doing lots of unnecessary things in the middle two lines. I tried to use intermediate directly like this:
let mut iter: Vec<u32> = a1.iter().chain(intermediate).map(|x| *x).collect();
But I am getting this error for chain method and I don't know how to solve it:
type mismatch resolving <I as std::iter::IntoIterator>::Item==&u32,
expected u32, found &u32
I am super new in Rust so any advice would be helpful to understand what's the right way to use intermediate parameter here.
Here are a few hints:
You have created three separate vectors (one explicitly, two using collect) when in fact you only need one.
You can use the std::iter::once iterator to produce iterators for the start and end integers
No need to collect the intermediate range. The intermediate argument implements IntoIterator, so you can feed it directly to chain. So, you can chain together the start, intermediate and end.
No need to use the 'return' keyword at the end of a function - the result of a function is the value of the last expression in it (as long as there is no semicolon on the end).
Applying those tips your function would look like this:
use std::iter::once;
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
once(start).chain(intermediate).chain(once(end)).collect()
}
One additional thing to note, to answer your question from the comments:
why trying this: a1.iter().chain(intermediate) gives an error with chain method
Calling Vec::iter() returns an iterator that returns references to the values in the vector. This makes sense: calling iter() does not consume the vector, and its contents remain intact: you could iterate over it multiple times if you wanted.
On the other hand, invoking into_iter() from the IntoIterator trait returns an iterator that returns the values. This also makes sense: into_iter() does consume the object you are calling it on, so the iterator then takes ownership of the items that were previously owned by the object.
Trying to chain together two such iterators does not work because they are each iterating different types. One resolution would be to consume a1 as well, like this:
let mut iter : Vec<u32> = a1.into_iter().chain(intermediate).collect();
I started to use clippy as a linter. Sometimes, it shows this warning:
writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be
used with non-Vec-based slices. Consider changing the type to `&[...]`,
#[warn(ptr_arg)] on by default
I changed the parameter to a slice but this adds boilerplate on the call side. For instance, the code was:
let names = args.arguments.iter().map(|arg| {
arg.name.clone()
}).collect();
function(&names);
but now it is:
let names = args.arguments.iter().map(|arg| {
arg.name.clone()
}).collect::<Vec<_>>();
function(&names);
otherwise, I get the following error:
error: the trait `core::marker::Sized` is not implemented for the type
`[collections::string::String]` [E0277]
So I wonder if there is a way to convert an Iterator to a slice or avoid having to specify the collected type in this specific case.
So I wonder if there is a way to convert an Iterator to a slice
There is not.
An iterator only provides one element at a time, whereas a slice is about getting several elements at a time. This is why you first need to collect all the elements yielded by the Iterator into a contiguous array (Vec) before being able to use a slice.
The first obvious answer is not to worry about the slight overhead, though personally I would prefer placing the type hint next to the variable (I find it more readable):
let names: Vec<_> = args.arguments.iter().map(|arg| {
arg.name.clone()
}).collect();
function(&names);
Another option would be for function to take an Iterator instead (and an iterator of references, at that):
let names = args.arguments.iter().map(|arg| &arg.name);
function(names);
After all, iterators are more general, and you can always "realize" the slice inside the function if you need to.
So I wonder if there is a way to convert an Iterator to a slice
There is. (in applicable cases)
Got here searching "rust iter to slice", for my use-case, there was a solution:
fn main() {
// example struct
#[derive(Debug)]
struct A(u8);
let list = vec![A(5), A(6), A(7)];
// list_ref passed into a function somewhere ...
let list_ref: &[A] = &list;
let mut iter = list_ref.iter();
// consume some ...
let _a5: Option<&A> = iter.next();
// now want to eg. return a slice of the rest
let slice: &[A] = iter.as_slice();
println!("{:?}", slice); // [A(6), A(7)]
}
That said, .as_slice is defined on an iter of an existing slice, so the previous answerer was correct in that if you've got, eg. a map iter, you would need to collect it first (so there is something to slice from).
docs: https://doc.rust-lang.org/std/slice/struct.Iter.html#method.as_slice
I'm having trouble combining two strings, I'm very new to rust so If there is an easier way to do this please feel free to show me.
My function loops through a vector of string tuples (String,String), what I want to do is be able to combine these two strings elements into one string. Here's what I have:
for tup in bmp.bitmap_picture.mut_iter() {
let &(ref x, ref y) = tup;
let res_string = x;
res_string.append(y.as_slice());
}
but I receive the error : error: cannot move out of dereference of '&'-pointer for the line: res_string.append(y.as_slice());
I also tried res_string.append(y.clone().as_slice()); but the exact same error happened, so I'm not sure if that was even right to do.
The function definition of append is:
fn append(self, second: &str) -> String
The plain self indicates by-value semantics. By-value moves the receiver into the method, unless the receiver implements Copy (which String does not). So you have to clone the x rather than the y.
If you want to move out of a vector, you have to use move_iter.
There are a few other improvements possible as well:
let string_pairs = vec![("Foo".to_string(),"Bar".to_string())];
// Option 1: leave original vector intact
let mut strings = Vec::new();
for &(ref x, ref y) in string_pairs.iter() {
let string = x.clone().append(y.as_slice());
strings.push(string);
}
// Option 2: consume original vector
let strings: Vec<String> = string_pairs.move_iter()
.map(|(x, y)| x.append(y.as_slice()))
.collect();
It seems like you might be confusing append, which takes the receiver by value and returns itself, with push_str, which simply mutates the receiver (passed by mutable reference) as you seem to expect. So the simplest fix to your example is to change append to push_str. You'll also need to change "ref x" to "ref mut x" so it can be mutated.