Rust 中元组的排序是如何定义的?

问题描述 投票:0回答:3

我正在查看文档,发现了一个看起来不熟悉的示例代码。

std::cmp::反向 - Rust

use std::cmp::Reverse;

let mut v = vec![1, 2, 3, 4, 5, 6];
v.sort_by_key(|&num| (num > 3, Reverse(num)));
assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);

(num > 3, Reverse(num))
如何定义它们之间的顺序?

我查看了 tuple 的文档,它说

元组的顺序性质适用于其各种特征的实现。例如,在 PartialOrd 和 Ord 中,顺序比较元素,直到找到第一个不相等的集合。

这对于相等性检查是有意义的,但在我看来,它没有解释

>
<
如何作用于元组。

我做了一些实验,但什么也不懂。

    println!("{}", (5, 5) > (3, 4)); // true
    println!("{}", (2, 2) > (3, 4)); // false
    println!("{}", (2, 5) > (3, 4)); // false
    println!("{}", (3, 5) > (3, 4)); // true
    println!("{}", (5, 2) > (3, 4)); // true
rust tuples
3个回答
19
投票

正如您引用的注释,元组是按字典顺序比较的。

也就是说,比较每个元组的第一个元素,如果它们相等,则比较第二个元素,然后是第三个元素,依此类推。直到找到不相等的对并提供元组的排序。如果所有对都相等,那么元组显然是相等的。

println!("{}", (5, 5) > (3, 4)); // true

5 > 3,因此 (5, _) > (3, _)

println!("{}", (2, 2) > (3, 4)); // false

2< 3, therefore (2, _) < (3, _)

println!("{}", (2, 5) > (3, 4)); // false

见上文

println!("{}", (3, 5) > (3, 4)); // true

3 == 3, 5 > 4,因此 (3, 5) > (3, 4)

println!("{}", (5, 2) > (3, 4)); // true

参见第一个案例

(num > 3, Reverse(num))
如何定义它们之间的顺序?

布尔排序

false < true
,因此它首先对两大类别中的元素进行排序(数字 3 或以下,然后数字大于 3),然后在每个类别中,项目根据其相反的自然顺序(即,最大在先)进行排序。尽管它显然是一次性完成的。


3
投票

您可以阅读

tuple
的源代码:

impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
    where last_type!($($T,)+): ?Sized {
    #[inline]
    fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
        lexical_partial_cmp!($(self.$idx, other.$idx),+)
    }
    // ...
    #[inline]
    fn gt(&self, other: &($($T,)+)) -> bool {
        lexical_ord!(gt, $(self.$idx, other.$idx),+)
    }
}

lexical_ord

// Constructs an expression that performs a lexical ordering using method $rel.
// The values are interleaved, so the macro invocation for
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
// a3, b3)` (and similarly for `lexical_cmp`)
macro_rules! lexical_ord {
    ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
        if $a != $b { lexical_ord!($rel, $a, $b) }
        else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
    };
    ($rel: ident, $a:expr, $b:expr) => { ($a) . $rel (& $b) };
}

因此

(a, b) > (c, d)
将调用
(a, b).gt(&(c, d))
,它将使用像这样的
lexical_ord
宏(请参阅代码中的注释):

lexical_ord(gt, a, c, b, d)

(实际上,如果我正确地阅读了宏,它应该类似于

lexical_ord(gt, (a, b).0, (c, d).0, (a, b).1, (c, d).1)
,但我在这里简化了它。)

这将被翻译(在编译时)为:

if a != c {
    (a).gt(&c)
} else {
    (b).gt(&d)
}

因此,

(a, b) > (c, d)
调用的实际代码将是:

fn gt(&self, other: &($T, $T)) -> bool {
    if self.0 != other.0 {
        (self.0).gt(&other.0)  // self.0 > other.0
    } else {
        (self.1).gt(&other.1)  // self.1 > other.1
    }
}

所以它是一对一地比较每个元组中的值。


1
投票

这对于相等性检查是有意义的,但在我看来,它没有解释

>
<
如何作用于元组。

确实如此,请考虑您给出的示例:

println!("{}", (5, 5) > (3, 4)); // 5 > 3 is true
println!("{}", (2, 2) > (3, 4)); // 2 > 3 is false
println!("{}", (2, 5) > (3, 4)); // 2 > 3 is false
println!("{}", (3, 5) > (3, 4)); // 3 == 3, then: 5 > 4 is true
println!("{}", (5, 2) > (3, 4)); // 5 > 3 is true

它返回元组第一个不相等元素的

<
/
>
的结果。

© www.soinside.com 2019 - 2024. All rights reserved.