LoginSignup
20
12

More than 1 year has passed since last update.

競プロで使えそうなRustのitertoolsのマクロとメソッドまとめ

Posted at

Rustのitertoolsなんとなく使っていたのですが、
時間とってどんなメソッドやマクロがあるのかなと眺めてみたので恣意的にピックアップしてまとめました。

順列、組み合わせ系

permutations

順列を返却してくれます。

let perms = (5..8).permutations(2);
itertools::assert_equal(perms, vec![
    vec![5, 6],
    vec![5, 7],
    vec![6, 5],
    vec![6, 7],
    vec![7, 5],
    vec![7, 6],
]);

combinations

名前の通り、組み合わせを返却してくれます。

let it = (1..5).combinations(3);
itertools::assert_equal(it, vec![
    vec![1, 2, 3],
    vec![1, 2, 4],
    vec![1, 3, 4],
    vec![2, 3, 4],
]);

tuple_combinations

組み合わせをtupleで返却してくれます。

let mut v = Vec::new();
for (a, b) in (1..5).tuple_combinations() {
    v.push((a, b));
}
assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]);

combinations_with_replacement

この記事をまとめるきっかけになったメソッドです。(重複組合せっていうらしい)
自前実装してたのですが、他の方の回答でこちら使っていて感動しました。

let it = (1..4).combinations_with_replacement(2);
itertools::assert_equal(it, vec![
    vec![1, 1],
    vec![1, 2],
    vec![1, 3],
    vec![2, 2],
    vec![2, 3],
    vec![3, 3],
]);

ループ系

iproduct!

2重ループや3重ループをすっきりかける。

// Iterate over the coordinates of a 4 x 4 x 4 grid
// from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3)
for (i, j, k) in iproduct!(0..4, 0..4, 0..4) {
   // ..
}

izip!

まとめてイテレーションしたいときに使えそう。

// iterate over three sequences side-by-side
let mut results = [0, 0, 0, 0];
let inputs = [3, 7, 9, 6];

for (r, index, input) in izip!(&mut results, 0..10, &inputs) {
    *r = index * 10 + input;
}

assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);

tuple_windows

基本的にはwindows()で事足りそうな気もするけど。。
重複なしの場合はtuples<T>(self)というメソッドも用意されている。

let mut v = Vec::new();
for (a, b) in (1..5).tuple_windows() {
    v.push((a, b));
}
assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]);

cartesian_product

直積。あんまり使う機会はなさそうですが・・・

let it = (0..2).cartesian_product("αβ".chars());
itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]);

インデックス検索系

positions

条件に一致するインデックスをVec<>で返却してくれます。
enumerateを使用しなくてもインデックスがわかるのは便利そうな気もします。

let data = vec![1, 2, 3, 3, 4, 6, 7, 9];

itertools::assert_equal(data.iter().positions(|v| v % 2 == 0), vec![1, 4, 5]);
itertools::assert_equal(data.iter().positions(|v| v % 2 == 1).rev(), vec![7, 6, 3, 2, 0]);

find_position

最小の要素を見つけ出すposition_min
最大の要素を見つけ出すposition_maxもあったので使えるかも。
どっちも欲しい場合はposition_minmaxもありました。

カスタムで順序制御したい場合のためにposition_min_byもあったので覚えておくといつか使えるかも。

let text = "Hα";
assert_eq!(text.chars().find_position(|ch| ch.is_lowercase()), Some((1, 'α')));

その他

merge

順序を制御したい場合はfn merge_by<J, F>(self, other: J, is_first: F)
もともとマージソートを自前で実装していたので、merge_byは便利かも。

let a = (0..11).step(3);
let b = (0..11).step(5);
let it = a.merge(b);
itertools::assert_equal(it, vec![0, 0, 3, 5, 6, 9, 10]);

unique

重複を飛ばしてくれる(ソートされていなくてもOK)
こちらもfn unique_by<V, F>(self, f: F)が用意されているので、カスタムして重複を削除できる。

let data = vec![10, 20, 30, 20, 40, 10, 50];
itertools::assert_equal(data.into_iter().unique(), vec![10, 20, 30, 40, 50]);

all_equal

すべてが同じかどうかを判定してくれます。そんなに需要はない気もしますが。。

let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5];
assert!(!data.iter().all_equal());
assert!(data[0..3].iter().all_equal());
assert!(data[3..5].iter().all_equal());
assert!(data[5..8].iter().all_equal());

tree_fold1

ぱっと使用法は思いつきませんでしたが面白かったので転記します笑

// The same tree as above
let num_strings = (1..8).map(|x| x.to_string());
assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)),
    Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))")));

// Like fold1, an empty iterator produces None
assert_eq!((0..0).tree_fold1(|x, y| x * y), None);

// tree_fold1 matches fold1 for associative operations...
assert_eq!((0..10).tree_fold1(|x, y| x + y),
    (0..10).fold1(|x, y| x + y));
// ...but not for non-associative ones
assert_ne!((0..10).tree_fold1(|x, y| x - y),
    (0..10).fold1(|x, y| x - y));
20
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
12