Is it possible to collect an iterator to populate

2019-08-09 06:41发布

Is it possible to collect an iterator such that it populates a collection backwards, such as using push_front in a VecDeque?

It's possible to collect into a Vec and then reverse it, but it seems like it should be unnecessary with data structures explicitly supporting this capability. I'd like to avoid writing an explicit for loop if possible.

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-09 07:10

Yes, it's possible:

use std::collections::VecDeque;

fn main() {
    let v: VecDeque<_> = (0..=2).collect_rev();
    assert_eq!(v, [2, 1, 0]);

    let v: Vec<_> = (0..=2).collect_rev();
    assert_eq!(v, [2, 1, 0]);
}

You just need a bit of glue code:

trait CollectRev: Iterator {
    fn collect_rev<B>(self) -> B
    where
        B: FromIteratorRev<Self::Item>,
        Self: Sized,
    {
        B::from_iter_rev(self)
    }
}

impl<I: Iterator> CollectRev for I {}

trait FromIteratorRev<T> {
    fn from_iter_rev(iter: impl IntoIterator<Item = T>) -> Self;
}

And implement it efficiently for various types:

impl<T> FromIteratorRev<T> for VecDeque<T> {
    fn from_iter_rev(iter: impl IntoIterator<Item = T>) -> Self {
        let mut v = Self::new();
        for i in iter {
            v.push_front(i);
        }
        v
    }
}

impl<T> FromIteratorRev<T> for Vec<T> {
    fn from_iter_rev(iter: impl IntoIterator<Item = T>) -> Self {
        let mut v: Self = iter.into_iter().collect();
        v.reverse();
        v
    }
}

I'd like to avoid writing an explicit for loop

Someone has to write that code.

查看更多
狗以群分
3楼-- · 2019-08-09 07:10

Is it possible to collect an iterator such that it populates a collection backwards, such as using push_front in a VecDeque?

Yes it is. You can iterate over your iterator with for_each and populate your VecDeque like this:

let mut my_deque: VecDeque<i32> = VecDeque::new();
(1..4).for_each(|x| my_deque.push_front(x));

You can reverse your iterator with the rev method. After that, you can call for_each to iterate it in the reverse order or you can collect it to a Vec directly since it is already reversed.

fn main() {
    let my_iterator = vec![1, 2, 3].into_iter();
    let reversed_iterator = my_iterator.rev();
    reversed_iterator.for_each(|x| print!("{}", x));
}

Or more idiomatically you can directly reverse it in your for loop:

for i in (1..4).rev() {
    print!("{}", i);
}

Your output will be:

321

Playground

查看更多
登录 后发表回答