[英]How do I replicate Haskell's `scanl (+) 0 xs` in Rust?
如果我有一個數字列表[1, 2, 3, 4, 5]
並且我想生成一個累積和列表,在Haskell中我將執行以下操作:
> let xs = [1, 2, 3, 4, 5]
> scanl (+) 0 xs
[0,1,3,6,10,15]
嘗試獲得相同的行為似乎在Rust中不必要地麻煩。
let xs = [1, 2, 3, 4, 5];
let vs = vec![0]
.into_iter()
.chain(xs.iter().scan(0, |acc, x| {
*acc += x;
Some(*acc)
}))
.collect::<Vec<_>>();
必須改變累加器的笨拙scan
行為可以通過缺少GC來解釋。 但是, scan
也不包括初始累加器值,因此需要在前面手動預置0。 這本身很麻煩,因為我需要在它前面添加chain
而[0].iter()
不起作用,也沒有[0].into_iter()
和vec![0].iter()
。 它需要vec![0].into_iter()
。
我覺得我必須在這里做錯事。 但是,什么? 有沒有更好的方法來生成累積金額? 是回到for
循環嗎?
盡管這個答案的舊版本模仿了scanl
的中間形式的行為,但執行並不是懶惰的。 使用@French Boiethios的答案更新了舊答案中的通用實現。
這是實施:
fn scanl<'u, T, F>(op: F, initial: T, list: &'u [T]) -> impl Iterator<Item = T> + 'u
where
F: Fn(&T, &T) -> T + 'u,
{
let mut iter = list.iter();
std::iter::successors(Some(initial), move |acc| iter.next().map(|n| op(n, acc)))
}
//scanl(|x, y| x + y, 0, &[1, 2, 3, 4, 5]).collect::<Vec<_>>()
它可以通過fold
輕松實現
對於Add
操作:
let result = xs.iter().fold(vec![0], |mut acc, val| {
acc.push(val + acc.last().unwrap());
acc
});
這是通用版本:
fn scanl<T, F>(op: F, initial: T, list: &[T]) -> Vec<T>
where
F: Fn(&T, &T) -> T,
{
let mut acc = Vec::with_capacity(list.len());
acc.push(initial);
list.iter().fold(acc, |mut acc, val| {
acc.push(op(val, acc.last().unwrap()));
acc
})
}
//scanl(|x, y| x + y, 0, &[1, 2, 3, 4, 5])
我會跟successors
這樣做:
fn main() {
let mut xs = vec![1, 2, 3, 4, 5].into_iter();
let vs = std::iter::successors(Some(0), |acc| xs.next().map(|n| n + *acc));
assert_eq!(vs.collect::<Vec<_>>(), [0, 1, 3, 6, 10, 15]);
}
必須改變累加器的笨拙掃描行為可以通過缺少GC來解釋。
什么都沒有阻止Rust做你所要求的。
可能的實施示例:
pub struct Mapscan<I, A, F> {
accu: Option<A>,
iter: I,
f: F,
}
impl<I, A, F> Mapscan<I, A, F> {
pub fn new(iter: I, accu: Option<A>, f: F) -> Self {
Self { iter, accu, f }
}
}
impl<I, A, F> Iterator for Mapscan<I, A, F>
where
I: Iterator,
F: FnMut(&A, I::Item) -> Option<A>,
{
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
self.accu.take().map(|accu| {
self.accu = self.iter.next().and_then(|item| (self.f)(&accu, item));
accu
})
}
}
trait IterPlus: Iterator {
fn map_scan<A, F>(self, accu: Option<A>, f: F) -> Mapscan<Self, A, F>
where
Self: Sized,
F: FnMut(&A, Self::Item) -> Option<A>,
{
Mapscan::new(self, accu, f)
}
}
impl<T: ?Sized> IterPlus for T where T: Iterator {}
fn main() {
let xs = [1, 2, 3, 4, 5];
let vs = xs
.iter()
.map_scan(Some(0), |acc, x| Some(acc + x));
assert_eq!(vs.collect::<Vec<_>>(), [0, 1, 3, 6, 10, 15]);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.