Reputation: 399
I have two iterators that will end up merging into the same Vec
, but I need to perform a filter on the end result before merging. For example:
let a = vec![1, 2, 3, 4].into_iter().map(|x| x * 2);
let b = vec![0, 3, 5, 6, 7].into_iter().map(|x| x * 3);
let c = a + b;
assert_eq!(
c.filter(|&x| x > 5).collect::<Vec<u8>>(),
vec![6, 8, 9, 15, 18, 21]
);
I could do something like this:
let mut a = vec![1, 2, 3, 4]
.into_iter()
.map(|x| x * 2)
.collect::<Vec<u8>>();
let b = vec![0, 3, 5, 6, 7]
.into_iter()
.map(|x| x * 3)
.collect::<Vec<u8>>();
a.extend(b);
assert_eq!(
a.into_iter().filter(|&x| x > 5).collect::<Vec<u8>>(),
vec![6, 8, 9, 15, 18, 21]
);
But the extra allocation kills performance in my case (yes, I checked!)
Upvotes: 12
Views: 16250
Reputation: 26767
Alternatively, you could use extend()
:
let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let mut c = Vec::with_capacity(a.size_hint().1.unwrap() + b.size_hint().1.unwrap());
c.extend(a);
c.extend(b);
This requires you to explicitly use with_capacity()
which chain()
and collect()
would have done for you. In the situation where a
is already constructed, extend()
will be suitable instead of building a temporary vector.
I did not find any benchmark difference between chain()
and extend
in this case (benchmark)
This doesn't do the filtering. Sebastian Redl
Correct! Fixing this mistake shows that for some reason, LLVM no longer optimizes chain()
now. The version with extend
:
let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let mut c = Vec::with_capacity(a.size_hint().1.unwrap() + b.size_hint().1.unwrap());
c.extend(a.filter(|&x| x > 5));
c.extend(b.filter(|&x| x > 5));
Is twice as fast than the version with chain
(this is what I expected in the first place):
let a = (0..500000).map(|x| x * 2);
let b = (0..500000).map(|x| x * 3);
let _c: Vec<_> = a.chain(b).filter(|&x| x > 5).collect();
Upvotes: 1
Reputation: 72063
You're looking for Iterator::chain
let a = vec![1, 2, 3, 4].into_iter().map(|x| x * 2);
let b = vec![0, 3, 5, 6, 7].into_iter().map(|x| x * 3);
let c = a.chain(b);
assert_eq!(
c.filter(|&x| x > 5).collect::<Vec<u8>>(),
vec![6, 8, 9, 15, 18, 21]
);
Upvotes: 24