概略
Rustで複数要素を持つデータの大きさを比較する際に便利なthen_with()メソッドの説明をします。
本記事の内容は、https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.then_with に説明を少し加えたものです。
単体のデータの比較
まず単体のデータで比較するときは下記のようにします。
比較の結果として、Less, Greater, Equalのいずれかが返されます。
fn main() {
// 比較時にはLess, Greater, Equalのいずれかが返される
let x = 1;
let y = 2;
let z = 1;
println!("{:?}", x.cmp(&y)); // Less
println!("{:?}", y.cmp(&x)); // Greater
println!("{:?}", x.cmp(&z)); // Equal
複数要素を持つデータの比較
次に複数要素を持つデータの比較します。
その際に使うのがthen_with()メソッドです。
then_with()メソッドの定義
- then_with()の直前がOrdering::Equalでない場合は、then_with()の直前のものを返す。
- then_with()の直前がOrdering::Equalである場合は、then_with()の中の処理を返す。
下記は使用例です。
use std::cmp::Ordering;
fn main() {
// 下記はthen_with()の直前が、Ordering::Equalなので、then_with()の中のOrdering::Lessを返す
let result = Ordering::Equal.then_with(|| Ordering::Less);
println!("{:?}", result); // Less
// 下記はthen_withの直前が、Ordering::Equalではない(Ordering::Less)なので、then_with()の直前のOrdering::Lessを返す
let result = Ordering::Less.then_with(|| Ordering::Equal);
println!("{:?}", result); // Less
then_with()メソッドを使った複数要素を持つデータの比較
実際に、then_with()メソッドを使って複数要素を持つデータの比較をしている例を下記に示します。
use std::cmp::Ordering;
fn main() {
// 下記のタプルの大小比較を考える
let x = (1, 2, 7);
let y = (1, 5, 3);
// 0個目の要素を比較する場合:
// x.0 = 1, y.0 = 1 => x.0 = y.1なのでOrdering::Equalを返す
let result = x.0.cmp(&y.0);
println!("{:?}", result); // Equal
// 1個目の要素を比較する場合:
// x.1 = 2, y.1 = 5 => x.1 < y.1なのでOrdering::Lessを返す
let result = x.0.cmp(&y.0);
println!("{:?}", result); // Less
// タプル全体の比較をする。
// 0個目の要素から比較を開始し、もし0個目の要素同士が等しければ1個目の要素を比較し、1個目の要素も等しければまた次の要素を比較していく
// 今回は0個目の要素が等しく、1個目の要素が比較対象より小さいので、Lessを返す
let result = x.0.cmp(&y.0).then_with(|| x.1.cmp(&y.1)).then_with(|| x.2.cmp(&y.2));
println!("{:?}", result); // Less
}
余談
then_with()メソッドについて知ったのは、C++のpriotiry_queueにあたるstd::collections::binary_heapで、最大値ではなく最小値を根にする為の実装方法を調べているときでした。
下記のページでthen_with()メソッドを使って、それを実現しているので、よかったらご参考下さい。
https://doc.rust-lang.org/std/collections/binary_heap/index.html