字符串以相反顺序连接Vec中的字符串而不使用`collect`

Ray*_*Ray 5 string iterator rust

我正在尝试将向量中的字符串连接到单个字符串中,与向量中的顺序相反.以下作品:

let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.iter().rev().map(|s| s.clone()).collect::<Vec<String>>().connect(".")
Run Code Online (Sandbox Code Playgroud)

但是,这最终会创建一个我实际上不需要的临时向量.有没有可能做到这一点collect?我看到这connect是一种StrVector方法.原始迭代器没有什么东西吗?

Vla*_*eev 10

我相信这是你能得到的最短的:

fn main() {
    let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    let mut r = v.iter()
        .rev()
        .fold(String::new(), |r, c| r + c.as_str() + ".");
    r.pop();
    println!("{}", r);
}
Run Code Online (Sandbox Code Playgroud)

添加String操作按值获取其左操作数并将第二个操作数原位推送,这非常好 - 它不会导致任何重新分配.你甚至不需要clone()包含的字符串.

但是,我认为迭代器上缺少concat()/ connect()方法是一个严重的缺点.它也让我很烦恼.


Art*_*mGr 7

我不知道他们是否听过我们的Stack Overflow祈祷或什么,但是itertools箱子碰巧只有你需要的方法 - join.

有了它,您的示例可能如下所示:

use itertools::Itertools;
let v = ["a", "b", "c"];
let connected = v.iter().rev().join(".");
Run Code Online (Sandbox Code Playgroud)


She*_*ter 5

这是我为您准备的迭代器扩展特性!

pub trait InterleaveExt: Iterator + Sized {
    fn interleave(self, value: Self::Item) -> Interleave<Self> {
        Interleave {
            iter: self.peekable(),
            value: value,
            me_next: false,
        }
    }
}

impl<I: Iterator> InterleaveExt for I {}

pub struct Interleave<I>
where
    I: Iterator,
{
    iter: std::iter::Peekable<I>,
    value: I::Item,
    me_next: bool,
}

impl<I> Iterator for Interleave<I>
where
    I: Iterator,
    I::Item: Clone,
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        // Don't return a value if there's no next item
        if let None = self.iter.peek() {
            return None;
        }

        let next = if self.me_next {
            Some(self.value.clone())
        } else {
            self.iter.next()
        };

        self.me_next = !self.me_next;
        next
    }
}
Run Code Online (Sandbox Code Playgroud)

可以这样调用:

fn main() {
    let a = &["a", "b", "c"];
    let s: String = a.iter().cloned().rev().interleave(".").collect();
    println!("{}", s);

    let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    let s: String = v.iter().map(|s| s.as_str()).rev().interleave(".").collect();
    println!("{}", s);
}
Run Code Online (Sandbox Code Playgroud)

从那以后,我了解到这个迭代器适配器已经以这个名字存在于 itertools 中intersperse——改用它吧!。

作弊答案

你从来没有说过你在这之后需要原始向量,所以我们可以原地反转它,只需使用join......

let mut v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.reverse();
println!("{}", v.join("."))
Run Code Online (Sandbox Code Playgroud)