【问题标题】:How do I check if a slice is sorted?如何检查切片是否已排序?
【发布时间】:2018-12-18 17:35:20
【问题描述】:

如何检查切片是否已排序?

假设一个函数接受i32 的切片,是否有一种惯用的 Rust 方法来检查切片是否已排序?

fn is_sorted(data: &[i32]) -> bool {
    // ...
}

是否可以概括上述方法,使其接受迭代器?

fn is_sorted<I>(iter: I)
where 
    I: Iterator, 
    I::Item: Ord,
{
    // ...
}

【问题讨论】:

  • 测试每个后续元素是否始终大于或小于前一个元素?
  • 作为记录,目前有一个RFC用于将is_sorted添加到标准库github.com/rust-lang/rfcs/pull/2351

标签: sorting iterator rust slice


【解决方案1】:

我会抓取成对的元素并断言它们都是升序(或降序,取决于你所说的“排序”的意思):

fn is_sorted<T>(data: &[T]) -> bool
where
    T: Ord,
{
    data.windows(2).all(|w| w[0] <= w[1])
}

fn main() {
    assert!(is_sorted::<u8>(&[]));
    assert!(is_sorted(&[1]));
    assert!(is_sorted(&[1, 2, 3]));
    assert!(is_sorted(&[1, 1, 1]));
    assert!(!is_sorted(&[1, 3, 2]));
    assert!(!is_sorted(&[3, 2, 1]));
}

泛型迭代器同上:

extern crate itertools; // 0.7.8

use itertools::Itertools;

fn is_sorted<I>(data: I) -> bool
where
    I: IntoIterator,
    I::Item: Ord + Clone,
{
    data.into_iter().tuple_windows().all(|(a, b)| a <= b)
}

fn main() {
    assert!(is_sorted(&[] as &[u8]));
    assert!(is_sorted(&[1]));
    assert!(is_sorted(&[1, 2, 3]));
    assert!(is_sorted(&[1, 1, 1]));
    assert!(!is_sorted(&[1, 3, 2]));
    assert!(!is_sorted(&[3, 2, 1]));
}

另见:

在 nightly Rust 中,有一些不稳定的方法可以做到这一点:

【讨论】:

  • @PeterHall 我不知道;通常,您要么保留按构造排序的集合(例如,始终在“正确”位置添加新值),要么按某种类型不变量(例如BTreeSet)。 有没有想过检查某些东西是否已排序? :-D 另外,那你还要处理 which 你的意思是“排序”,然后按一个键排序,等等。
  • @Shepmaster "你有没有想过检查某些东西是否已排序?" -- 实际上经常:单元测试和前置/后置条件检查。 I've written a few more words about this here ;-)
  • 我觉得很明显,这需要(总)订单,而不是部分订单。从来没有想过这个。
【解决方案2】:

对于迭代器is_sorted 实现,不需要Clone。这是 is_sorted 的无依赖 Rust 实现:

fn is_sorted<I>(data: I) -> bool
where
    I: IntoIterator,
    I::Item: Ord,
{
    let mut it = data.into_iter();
    match it.next() {
        None => true,
        Some(first) => it.scan(first, |state, next| {
            let cmp = *state <= next;
            *state = next;
            Some(cmp)
        }).all(|b| b),
    }
}

【讨论】:

    【解决方案3】:

    还有一个使用try_fold()

    pub fn is_sorted<T: IntoIterator>(t: T) -> bool
    where
        <T as IntoIterator>::Item: std::cmp::PartialOrd,
    {
        let mut iter = t.into_iter();
    
        if let Some(first) = iter.next() {
            iter.try_fold(first, |previous, current| {
                if previous > current {
                    Err(())
                } else {
                    Ok(current)
                }
            })
            .is_ok()
        } else {
            true
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 2016-09-23
      • 1970-01-01
      • 2013-08-09
      • 2017-03-13
      • 2017-11-20
      • 2012-04-08
      • 1970-01-01
      • 2011-06-10
      相关资源
      最近更新 更多