如何知道所有切片元素是否相等,如果相等,return 对第一个元素的引用?

How to know if all slice elements are equal, and if so, return a reference to the first one?

给定任何切片,例如:

let words = &["one", "one", "one", "two"];

如何知道所有元素是否相同?

更进一步,如果所有元素都相同,如何return引用第一个?

本质上,我正在尝试编写如下函数:

fn are_all_elements_equal<T>(elems: &[T]) -> Option<&T> {
    // ... ?
}

我会使用 .allhttps://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all

首先,如果切片为空,则return None.

然后为自己获取一个遍历切片其余部分的迭代器,并使用 .all 函数检查该元素是否等于您刚刚获取的第一个元素。如果 return 是真的,return 你的 Some(first_element)

一个优雅的方法是使用 itertools 箱子中的 tuple_windows

use itertools::Itertools;

pub fn are_all_elements_equal<T: Eq>(elems: &[T]) -> Option<&T> {
    elems.iter().tuple_windows().all(|(a, b)| a == b).then(|| &elems[0])
}

请注意,这会在空切片上出现恐慌。要处理空切片,您需要显式 return None if elems.is_empty().

使用可用的内置函数非常简单:

fn check_all<T: Eq>(items: &[T]) -> Option<&T> {
    match items.is_empty() {
        true => None,
        false => items.windows(2).all(|a| a[0] == a[1]).then(|| &items[0])
    }
}

Playground link

  • .windows(2) 为您提供包含重叠元素对的迭代器。
  • .all(|a| a[0] == a[1]) 比较每个 window
  • 中的两个元素
  • .then(|| &items[0]) returns 一个 Option 包含对第一个元素的引用,如果前一个 .all() returns true,否则它 returns None
  • match items.is_empty() 是必需的,因为如果切片为空,.all() 也会 return true,这将导致 items[0][ 出现恐慌=38=]

请注意,由于 .all() 中使用的比较可能会导致相同的值与自身进行比较,因此您需要将 T 限制为 Eq

作为对已发布答案的扩展,您还可以将其通用化为可以迭代的任何内容:

pub fn iter_all_eq<T: PartialEq>(iter: impl IntoIterator<Item = T>) -> Option<T> {
    let mut iter = iter.into_iter();
    let first = iter.next()?;
    iter.all(|elem| elem == first).then(|| first)
}

fn main() {
    println!("{:?}", iter_all_eq(&[1, 1, 1]));
    println!("{:?}", iter_all_eq(&[1, 2, 1]));
    println!("{:?}", iter_all_eq(&["abc", "abc", "abc", "abc"]));
}

Playground

我认为这是子切片模式的一个很好的用例:

pub fn are_all_elements_equal<T: PartialEq>(elems: &[T]) -> Option<&T> {
    match elems {
        [head, tail @ ..] => tail.iter().all(|x| x == head).then(|| head),
        [] => None,
    }
}