2017-12-24 7 views
0

私はシーケンス(リスト、イテレータ)a0, a1, a2, ...を持っており、私は関数fを使ってフォールドします。私は、これはMathematicaでFoldListに似ている私に連続折り畳み結果を繰り返し処理するための慣用的で機能的な方法は何ですか?

a0, f(a0, a1), f(f(a0, a1), a2), ... 

を与える発電機を持っていると思います。利用可能な機能はfold_listですか?私は何も見つけることができませんでした。

答えて

2

最も近い抽象化はIterator::scanです。内部的な変更可能な状態(結果として得られるイテレータに異なる値を与えることができる)があり、早期に中止することができるため、少し強力です。

あなたはイテレータ拡張形質を構築するために、このようにそれを使用することができます。

Playground

pub trait FoldListExt: Iterator { 
    fn fold_list<'a, St: 'a, F: 'a>(self, initial_state: St, f: F) -> Box<Iterator<Item = St> + 'a> 
    where 
     St: Clone, 
     F: FnMut(St, Self::Item) -> St, 
     Self: 'a; 
} 

impl<I: Iterator> FoldListExt for I { 
    fn fold_list<'a, St: 'a, F: 'a>(
     self, 
     initial_state: St, 
     mut f: F, 
    ) -> Box<Iterator<Item = St> + 'a> 
    where 
     St: Clone, 
     F: FnMut(St, Self::Item) -> St, 
     Self: 'a, 
    { 
     Box::new(self.scan(Some(initial_state), move |state, item| { 
      let old_state = state.take().unwrap(); 
      *state = Some(f(old_state.clone(), item)); 
      Some(old_state) 
     })) 
    } 
} 

pub fn main() { 
    println!(
     "{:?}", 
     (0..16) 
      .into_iter() 
      .fold_list(0, |a, b| a + b) 
      .collect::<Vec<_>>() 
    ); 
} 

私は別のclone()呼び出しを避けるために、内部可変状態のためOption<St>を使用していました。

あなたは代わりにこれを使用することができます:

Box::new(self.scan(initial_state, move |state, item| { 
    let old_state = state.clone(); 
    *state = f(old_state.clone(), item); 
    Some(old_state) 
})) 
+0

おかげで、完璧! –

関連する問題