I have a Vec of integers and I want to create a new Vec which contains those integers and squares of those integers. I could do this imperatively:
let v = vec![1, 2, 3];
let mut new_v = Vec::new(); // new instead of with_capacity for simplicity sake.
for &x in v.iter() {
new_v.push(x);
new_v.push(x * x);
}
println!("{:?}", new_v);
but I want to use iterators. I came up with this code:
let v = vec![1, 2, 3];
let new_v: Vec<_> = v.iter()
.flat_map(|&x| vec![x, x * x])
.collect();
println!("{:?}", new_v);
but it allocates an intermediate Vec in the flat_map function.
How to use flat_map without allocations?
As of Rust 1.53.0, this can be written with just the array literal:
let v = vec![1, 2, 3];
let new_v: Vec<_> = v.iter()
.flat_map(|&x| [x, x * x])
.collect();
Rust 1.53.0 implements IntoIterator for arrays, so the vec![] and workarounds in previous solutions are no longer needed. This works on all editions.
If your iterator is small and you don't want any external dependencies, a short iterator can be constructed from std::iter::once and std::iter::Iterator::chain. For example,
use std::iter;
let v = vec![1, 2, 3];
let new_v: Vec<_> = v
.iter()
.flat_map(|&x| iter::once(x).chain(iter::once(x * x)))
.collect();
println!("{:?}", new_v);
(playground)
This could be made into a macro, though be aware that using this for too many elements may cause the recursion limit to be reached. If you're making an iterator for more than a few dozen elements, it's probably not too bad to have an allocation. If you really need the slight increase in performance, nnnmmm's solution is probably better.
macro_rules! small_iter {
() => { std::iter::empty() };
($x: expr) => {
std::iter::once($x)
};
($x: expr, $($y: tt)*) => {
std::iter::once($x).chain(small_iter!($($y)*))
};
}
fn main() {
let v = vec![1, 2, 3];
let new_v: Vec<_> = v
.iter()
.flat_map(|&x| small_iter!(x, x * x))
.collect();
println!("{:?}", new_v);
}
(playground)
As of version 1.51.0, the struct core::array::IntoIter has been stabilized. You can use it like this:
use core::array;
let v = vec![1, 2, 3];
let new_v: Vec<_> = v.iter()
.flat_map(|&x| array::IntoIter::new([x, x * x]))
.collect();
The documentation warns that this may be deprecated in the future when IntoIterator is implemented for arrays, but currently it's the easiest way to do this.
You can use an ArrayVec for this.
let v = vec![1, 2, 3];
let new_v: Vec<_> = v.iter()
.flat_map(|&x| ArrayVec::from([x, x * x]))
.collect();
Making arrays be by-value iterators, so that you wouldn't need ArrayVec has been discussed, see https://github.com/rust-lang/rust/issues/25725 and the linked PRs.
Related
I'm trying to figure out an efficient Rust way of consuming elements of a vector and replacing them with one or more elements (of the same type) like in the non-compiling example:
fn main() {
let mut myvec = vec![0, 1];
println!("{:?}", myvec);
for val in myvec.drain(..) {
myvec.push(val+2);
myvec.push(val+4);
}
println!("{:?}", myvec);
}
However, I am not even sure if Rust would even allow that as each operation needs a mutable reference (i.e. we need 2 mutable refs) but Rust can only allow one. Is there a way doing what I want to do or do I just need to have 2 separate vectors:
let mut myvec = vec![0, 1];
let mut newvec = Vec::new();
println!("{:?}", myvec);
for val in myvec.drain(..) {
newvec.push(val+2);
newvec.push(val+4);
}
println!("{:?}", newvec);
which outputs:
[0, 1]
[2, 4, 3, 5]
PS. I know that the splice method can achieve what I need but I also need a mutable reference inside the for loop.
Since you are changing the size of the Vec, it's likely that it will need reallocation anyway. Additionally, you cannot mutate a Vec while you are iterating it (precisely because mutating it could cause it to reallocate). It won't be much different to collect into a new Vec:
myvec = myvec
.drain(..)
.flat_map(|val| iter::once(val + 2).chain(iter::once(val + 4)))
.collect();
The chained iterator might not be as optimal as it could be. In nightly Rust, you could do:
#![feature(array_value_iter)]
use std::array;
myvec = myvec
.drain(..)
.flat_map(|val| array::IntoIter::new([val + 2, val + 4]))
.collect();
Which should be more efficient.
You could swap elements of the same type directly in memory:
use core::mem::swap;
fn main() {
let mut myvec = vec![0, 1];
let mut result = Vec::new();
println!("{:?}", myvec);
for i in (0..myvec.len()).step_by(2) {
let mut x = myvec[i] + 2;
swap(&mut myvec[i], &mut x);
result.push(x);
if i + 1 < myvec.len() {
let mut y = myvec[i + 1] + 4;
swap(&mut myvec[i + 1], &mut y);
result.push(y);
}
}
println!("{:?} {:?}", myvec, result);
}
After posting I realized that you require replacing an element with more than one element, and this code won't do that. I'll leave it up in case it helps, though.
This code works correctly and gives the result as 14:
fn main() {
let v: i32 = vec![1, 2, 3].iter().map(|x| x * x).sum();
println!("{}", v);
}
playground
I'm trying to replace the x * x by powi(2) so I tried both options below, but neither of them work:
let v1: i32 = vec![1, 2, 3].iter().map(|x| x.powi(2)).sum();
let v2: i32 = vec![1, 2, 3].iter().map(|&x| &x.powi(2)).sum();
I've also posted this to the Rust user's forum.
In the standard library, powi is only implemented for the two built-in floating point types:
f32::powi
f64::powi
If you wish to apply a power to an integer type, you want to use the inherent method pow (e.g. i32::pow):
let v: i32 = vec![1i32, 2, 3].iter().map(|x| x.pow(2)).sum();
I have this toy example, but it's what I'm trying to accomplish:
fn lazy_vec() {
let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
let mut iter: Box<Iterator<Item = i64>> = Box::new(vec.into_iter());
iter = Box::new(iter.map(|x| x + 1));
// potentially do additional similar transformations to iter
println!("{:?}", iter.collect::<Vec<_>>());
}
This (if I'm not mistaken) is a lazy iterator pattern, and the actual map operation doesn't occur until .collect() is called. I want to do the same thing with slices:
fn lazy_slice() {
let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
let slice: &[i64] = &vec[..3];
let mut iter: Box<Iterator<Item = i64>> = Box::new(slice.into_iter());
iter = Box::new(iter.map(|x| x + 1));
// potentially do additional similar transformations to iter
println!("{:?}", iter.collect::<Vec<_>>());
}
This results in a type mismatch:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, i64> as std::iter::Iterator>::Item == i64`
--> src/main.rs:4:47
|
4 | let mut iter: Box<Iterator<Item = i64>> = Box::new(slice.into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found i64
|
= note: expected type `&i64`
found type `i64`
= note: required for the cast to the object type `std::iter::Iterator<Item=i64>`
I can't figure out what I need to do to resolve this error. The second note made me think I needed:
iter = Box::new(iter.map(|x| x + 1) as Iterator<Item = i64>);
or
iter = Box::new(iter.map(|x| x + 1)) as Box<Iterator<Item = i64>>;
These fail with other errors depending on the exact syntax (e.g. expected reference, found i64, or expected i64, found &i64). I've tried other ways to declare the types involved, but I'm basically just blindly adding & and * in places and not making any progress.
What am I missing here? What do I need to change in order to make this compile?
Edit
Here's a slightly more concrete example - I need iter to be mut so that I can compose an unknown number of such transformations before actually invoking .collect(). My impression was this was a somewhat common pattern, apologies if that wasn't correct.
fn lazy_vec(n: i64) {
let vec: Vec<i64> = vec![1, 2, 3, 4, 5];
let mut iter: Box<Iterator<Item = i64>> = Box::new(vec.into_iter());
for _ in 0..n {
iter = Box::new(iter.map(|x| x + 1));
}
println!("{:?}", iter.collect::<Vec<_>>());
}
I'm aware I could rewrite this specific task in a simpler way (e.g. a single map that adds n to each element) - it's an oversimplified MCVE of the problem I'm running into. My issue is this works for lazy_vec, but I'm not sure how to do the same with slices.
Edit 2
I'm just learning Rust and some of the nomenclature and concepts are new to me. Here's what I'm envisioning doing in Python, for comparison. My intent is to do the same thing with slices that I can currently do with vectors.
#!/usr/bin/env python3
import itertools
ls = [i for i in range(10)]
def lazy_work(input):
for i in range(10):
input = (i + 1 for i in input)
# at this point no actual work has been done
return input
print("From list: %s" % list(lazy_work(ls)))
print("From slice: %s" % list(lazy_work(itertools.islice(ls, 5))))
Obviously in Python there's no issues with typing, but hopefully that more clearly demonstrates my intent?
As discussed in What is the difference between iter and into_iter?, these methods create iterators which yield different types when called on a Vec compared to a slice.
[T]::iter and [T]::into_iter both return an iterator which yields values of type &T. That means that the returned value doesn't implement Iterator<Item = i64> but instead Iterator<Item = &i64>, as the error message states.
However, your subsequent map statements change the type of the iterator's item to an i64, which means the type of the iterator would also need to change. As an analogy, you've essentially attempted this:
let mut a: &i64 = &42;
a = 99;
Iterator::cloned exists to make clones of the iterated value. In this case, it converts a &i64 to an i64 essentially dereferencing the value:
fn lazy_slice(n: i64) {
let array = [1i64, 2, 3, 4, 5];
let mut iter: Box<Iterator<Item = i64>> = Box::new(array.iter().cloned());
for _ in 0..n {
iter = Box::new(iter.map(|x| x + 1));
}
println!("{:?}", iter.collect::<Vec<_>>());
}
I want to take the x first and last elements from a vector and concatenate them. I have the following code:
fn main() {
let v = (0u64 .. 10).collect::<Vec<_>>();
let l = v.len();
vec![v.iter().take(3), v.iter().skip(l-3)];
}
This gives me the error
error[E0308]: mismatched types
--> <anon>:4:28
|
4 | vec![v.iter().take(3), v.iter().skip(l-3)];
| ^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Take`, found struct `std::iter::Skip`
<anon>:4:5: 4:48 note: in this expansion of vec! (defined in <std macros>)
|
= note: expected type `std::iter::Take<std::slice::Iter<'_, u64>>`
= note: found type `std::iter::Skip<std::slice::Iter<'_, u64>>`
How do I get my vec of 1, 2, 3, 8, 9, 10? I am using Rust 1.12.
Just use .concat() on a slice of slices:
fn main() {
let v = (0u64 .. 10).collect::<Vec<_>>();
let l = v.len();
let first_and_last = [&v[..3], &v[l - 3..]].concat();
println!("{:?}", first_and_last);
// The output is `[0, 1, 2, 7, 8, 9]`
}
This creates a new vector, and it works with arbitrary number of slices.
(Playground link)
Ok, first of all, your initial sequence definition is wrong. You say you want 1, 2, 3, 8, 9, 10 as output, so it should look like:
let v = (1u64 .. 11).collect::<Vec<_>>();
Next, you say you want to concatenate slices, so let's actually use slices:
let head = &v[..3];
let tail = &v[l-3..];
At this point, it's really down to which approach you like the most. You can turn those slices into iterators, chain, then collect...
let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
...or make a vec and extend it with the slices directly...
let mut v3 = vec![];
v3.extend_from_slice(head);
v3.extend_from_slice(tail);
...or extend using more general iterators (which will become equivalent in the future with specialisation, but I don't believe it's as efficient just yet)...
let mut v4: Vec<u64> = vec![];
v4.extend(head);
v4.extend(tail);
...or you could use Vec::with_capacity and push in a loop, or do the chained iterator thing, but using extend... but I have to stop at some point.
Full example code:
fn main() {
let v = (1u64 .. 11).collect::<Vec<_>>();
let l = v.len();
let head = &v[..3];
let tail = &v[l-3..];
println!("head: {:?}", head);
println!("tail: {:?}", tail);
let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
println!("v2: {:?}", v2);
let mut v3 = vec![];
v3.extend_from_slice(head);
v3.extend_from_slice(tail);
println!("v3: {:?}", v3);
// Explicit type to help inference.
let mut v4: Vec<u64> = vec![];
v4.extend(head);
v4.extend(tail);
println!("v4: {:?}", v4);
}
You should collect() the results of the take() and extend() them with the collect()ed results of skip():
let mut p1 = v.iter().take(3).collect::<Vec<_>>();
let p2 = v.iter().skip(l-3);
p1.extend(p2);
println!("{:?}", p1);
Edit: as Neikos said, you don't even need to collect the result of skip(), since extend() accepts arguments implementing IntoIterator (which Skip does, as it is an Iterator).
Edit 2: your numbers are a bit off, though; in order to get 1, 2, 3, 8, 9, 10 you should declare v as follows:
let v = (1u64 .. 11).collect::<Vec<_>>();
Since the Range is left-closed and right-open.
Although vectors are best suited for procedural programming, I would like to use a map function on them. The following snippet works:
fn map<A, B>(u: &Vec<A>, f: &Fn(&A) -> B) -> Vec<B> {
let mut res: Vec<B> = Vec::with_capacity(u.len());
for x in u.iter() {
res.push(f(x));
}
res
}
fn f(x: &i32) -> i32 {
*x + 1
}
fn main() {
let u = vec![1, 2, 3];
let v = map(&u, &f);
println!("{} {} {}", v[0], v[1], v[2]);
}
Why isn't there any such function in the standard library (and also in std::collections::LinkedList)? Is there another way to deal with it?
Rust likes to be more general than that; mapping is done over iterators, rather than over solely vectors or slices.
A couple of demonstrations:
let u = vec![1, 2, 3];
let v: Vec<_> = u.iter().map(f).collect();
let u = vec![1, 2, 3];
let v = u.iter().map(|&x| x + 1).collect::<Vec<_>>();
.collect() is probably the most magic part of it, and allows you to collect all the elements of the iterator into a large variety of different types, as shown by the implementors of FromIterator. For example, an iterator of Ts can be collected to Vec<T>, of chars can be collected to a String, of (K, V) pairs to a HashMap<K, V>, and so forth.
This way of working with iterators also means that you often won’t even need to create intermediate vectors where in other languages or with other techniques you would; this is more efficient and typically just as natural.
As pointed out by bluss, you can also use the mutable iterator to mutate the value in place, without changing the type:
let mut nums = nums;
for num in &mut nums { *num += 1 }
println!("{:p} - {:?}", &nums, nums);
The function Vec::map_in_place was deprecated in Rust 1.3 and is no longer present in Rust 1.4.
Chris Morgan's answer is the best solution 99% of the time. However, there is a specialized function called Vec::map_in_place. This has the benefit of not requiring any additional memory allocations, but it requires that the input and output type are the same size (thanks Levans) and is currently unstable:
fn map_in_place<U, F>(self, f: F) -> Vec<U>
where F: FnMut(T) -> U
An example:
#![feature(collections)]
fn main() {
let nums = vec![1,2,3];
println!("{:p} - {:?}", &nums, nums);
let nums = nums.map_in_place(|v| v + 1);
println!("{:p} - {:?}", &nums, nums);
}