字符串以相反的顺序加入 Vec 中的字符串,没有“收集”
String join on strings in Vec in reverse order without a `collect`
我正在尝试将向量中的字符串连接成单个字符串,与它们在向量中的顺序相反。以下作品:
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.iter().rev().map(|s| s.clone()).collect::<Vec<String>>().connect(".")
但是,这最终创建了一个我实际上并不需要的临时向量。没有 collect
是否可以做到这一点?我看到 connect
是一个 StrVector
方法。没有原始迭代器吗?
我相信这是最短的:
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);
}
String
上的加法运算按值获取其左操作数并将第二个操作数就地压入,这非常好 - 它不会导致任何重新分配。您甚至不需要 clone()
包含的字符串。
不过,我认为迭代器缺少 concat()
/connect()
方法是一个严重的缺点。它也让我很痛苦。
这是我为你设计的迭代器扩展特征!
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
}
}
可以这样调用:
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);
}
从那以后,我了解到这个迭代器适配器已经存在于 itertools 中,名称为 intersperse
— 请改用它!
作弊回答
你从来没有说过你需要之后的原始向量,所以我们可以原地反转它,只需要使用join
...
let mut v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.reverse();
println!("{}", v.join("."))
我不知道他们是否听到了我们的 Stack Overflow 祈祷之类的,但是 itertools crate happens to have just the method you need - join
。
有了它,您的示例可能会如下所示:
use itertools::Itertools;
let v = ["a", "b", "c"];
let connected = v.iter().rev().join(".");
我正在尝试将向量中的字符串连接成单个字符串,与它们在向量中的顺序相反。以下作品:
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.iter().rev().map(|s| s.clone()).collect::<Vec<String>>().connect(".")
但是,这最终创建了一个我实际上并不需要的临时向量。没有 collect
是否可以做到这一点?我看到 connect
是一个 StrVector
方法。没有原始迭代器吗?
我相信这是最短的:
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);
}
String
上的加法运算按值获取其左操作数并将第二个操作数就地压入,这非常好 - 它不会导致任何重新分配。您甚至不需要 clone()
包含的字符串。
不过,我认为迭代器缺少 concat()
/connect()
方法是一个严重的缺点。它也让我很痛苦。
这是我为你设计的迭代器扩展特征!
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
}
}
可以这样调用:
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);
}
从那以后,我了解到这个迭代器适配器已经存在于 itertools 中,名称为 intersperse
— 请改用它!
作弊回答
你从来没有说过你需要之后的原始向量,所以我们可以原地反转它,只需要使用join
...
let mut v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
v.reverse();
println!("{}", v.join("."))
我不知道他们是否听到了我们的 Stack Overflow 祈祷之类的,但是 itertools crate happens to have just the method you need - join
。
有了它,您的示例可能会如下所示:
use itertools::Itertools;
let v = ["a", "b", "c"];
let connected = v.iter().rev().join(".");