[Rust] イテレータで直積集合を生成

適当に作ったので間違ってると思います。適宜修正して使ってください。

**注意** 一番簡単かつ普通なのは[こちらの方法](https://qiita.com/yasuo-ozu/items/38cca853ee63bf97d0db#comment-3d79a537c7663ab85e7a)です。本文中のコードはかなり変態なので、これを見てRustのことを嫌いにならないでください。

# モチベーション

```rs
let v = vec![1, 2];
let w = vec![3, 4];
```

という2つの集合が与えられた時、

```
(1, 3)
(1, 4)
(2, 3)
(2, 4)
```

というペアのイテレータを取得したい。

# Code

```rs
struct Cross<T: Iterator, U: Iterator + Clone>(T, U, Option<T::Item>, Option<U>)
where
    T::Item: Clone;

fn cross<T, U>(this: T, other: U) -> Cross<T::IntoIter, U::IntoIter>
where
    T: IntoIterator,
    T::Item: Clone,
    U: IntoIterator,
    U::IntoIter: Clone,
{
    Cross(this.into_iter(), other.into_iter(), None, None)
}
impl<T, U> Iterator for Cross<T, U>
where
    T: Iterator,
    T::Item: Clone,
    U: Iterator + Clone,
{
    type Item = (T::Item, U::Item);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if let None = self.2 {
            if let Some(v1) = self.0.next() {
                self.2 = Some(v1);
            } else {
                return None;
            }
        }
        if let None = self.3 {
            self.3 = Some(self.1.clone())
        }
        if let Some(v2) = self.3.as_mut().unwrap().next() {
            Some((self.2.as_ref().unwrap().clone(), v2))
        } else {
            self.2 = None;
            self.3 = None;
            self.next()
        }
    }
}
fn main() {
    let v = vec![1, 2, 3];
    let w = vec![4, 5, 6];
    for (i, j) in cross(v, w) {
        println!("({}, {})", i, j);
    }
}
```

# (追加) 別のバージョン

標準ライブラリを用いて手を抜いた...つもりが前のバージョンより時間がかかりました

```rs
use std::iter::{Cycle, FlatMap, Map, Zip};
use std::vec::IntoIter;
fn product<S, T>(
    ls: S,
    rs: T,
) -> FlatMap<
    Zip<S::IntoIter, Cycle<IntoIter<T>>>,
    Map<Zip<T::IntoIter, Cycle<IntoIter<S::Item>>>, fn((T::Item, S::Item)) -> (S::Item, T::Item)>,
    fn(
        (S::Item, T),
    ) -> Map<
        Zip<T::IntoIter, Cycle<IntoIter<S::Item>>>,
        fn((T::Item, S::Item)) -> (S::Item, T::Item),
    >,
>
where
    S: IntoIterator,
    T: IntoIterator + Clone,
    S::Item: Clone,
{
    ls.into_iter()
        .zip(vec![rs].into_iter().cycle())
        .flat_map(|(l, rs)| {
            rs.into_iter()
                .zip(vec![l].into_iter().cycle())
                .map(|(r, l)| (l, r))
        })
}

fn main() {
    let xs = vec![1, 2, 3];
    let ys = vec![4, 5, 6];

    println!("{:?}", product(xs, ys).collect::<Vec<_>>());
}
```

外部の変数をキャプチャするクロージャの型修飾をうまく書けないので、無理やり`zip`と`cycle`を用いてキャプチャする変数を引数に持っていった。

タイプエイリアスを使ったら簡単になるかなと思ったけど大して変わらなかった

```rs
use std::iter::{Cycle, FlatMap, Map, Zip};
use std::vec::IntoIter;
type M<S, T> = Map<
    Zip<<T as IntoIterator>::IntoIter, Cycle<IntoIter<<S as IntoIterator>::Item>>>,
    fn(
        (<T as IntoIterator>::Item, <S as IntoIterator>::Item),
    ) -> (<S as IntoIterator>::Item, <T as IntoIterator>::Item),
>;
fn product<S, T>(
    ls: S,
    rs: T,
) -> FlatMap<Zip<S::IntoIter, Cycle<IntoIter<T>>>, M<S, T>, fn((S::Item, T)) -> M<S, T>>
where
    S: IntoIterator,
    T: IntoIterator + Clone,
    S::Item: Clone,
{
    ls.into_iter()
        .zip(vec![rs].into_iter().cycle())
        .flat_map(|(l, rs)| {
            rs.into_iter()
                .zip(vec![l].into_iter().cycle())
                .map(|(r, l)| (l, r))
        })
}

fn main() {
    let xs = vec![1, 2, 3];
    let ys = vec![4, 5, 6];

    println!("{:?}", product(xs, ys).collect::<Vec<_>>());
}
```

これは`Impl Trait`を用いると[さらに簡単になります。](https://qiita.com/yasuo-ozu/items/38cca853ee63bf97d0db#comment-e06a575716c130c8b9a3)

# (追加) もう少し理解しやすいバージョン

内側のループでイテレータではなくVecを生成するようにした。

```rs
use std::iter::{Cycle, FlatMap, Zip};
use std::vec::IntoIter;
fn product<S, T>(
    ls: S,
    rs: T,
) -> FlatMap<
    Zip<S::IntoIter, Cycle<IntoIter<T>>>,
    Vec<(S::Item, T::Item)>,
    fn((S::Item, T)) -> Vec<(S::Item, T::Item)>,
>
where
    S: IntoIterator,
    T: IntoIterator + Clone,
    S::Item: Clone,
{
    ls.into_iter()
        .zip(vec![rs].into_iter().cycle())
        .flat_map(|(l, rs)| rs.into_iter().map(|r| (l.clone(), r)).collect::<Vec<_>>())
}

fn main() {
    let xs = vec![1, 2, 3];
    let ys = vec![4, 5, 6];

    println!("{:?}", product(xs, ys).collect::<Vec<_>>());
}
```

# おわりに

標準ライブラリでやる方法があったら教えてください

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/rustlang?src=hash&amp;ref_src=twsrc%5Etfw">#rustlang</a> の <a href="https://twitter.com/hashtag/iterator?src=hash&amp;ref_src=twsrc%5Etfw">#iterator</a> で直積集合をうまく作る方法ないかな?<br>今の所、fold()で適当にやってるけど</p>&mdash; yasuo_ozu (@yasuo_ozu) <a href="https://twitter.com/yasuo_ozu/status/1304785976011546631?ref_src=twsrc%5Etfw">September 12, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>