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



给定任意切片,例如:

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

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

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

本质上,我想写一个这样的函数:

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

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

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,
}
}

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

首先,如果切片为空,只返回None

然后在切片的其余部分抓取一个迭代器,并使用.all函数检查该元素是否等于您刚刚抓取的第一个元素。如果返回true,则返回Some(first_element)

作为已经发布的答案的扩展,您还可以将其用于任何可以迭代的泛型:

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"]));
}

游乐场

一种优雅的方法是使用itertoolscrate中的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])
}

请注意,这将在空片上出错。为了处理空片,如果elems.is_empty(),则需要显式地返回None

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

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])
}
}

操场上联系

  • .windows(2)给出一个包含重叠元素对的迭代器。
  • .all(|a| a[0] == a[1])比较来自每个窗口的两个元素
  • 如果前一个.all()返回true,则.then(|| &items[0])返回包含对第一个元素引用的Option,否则返回None
  • match items.is_empty()是必需的,因为如果片为空,.all()也将返回true,这将导致items[0]
  • 的恐慌

请注意,由于.all()中使用的比较可能导致与自身比较的值相同,因此根据此答案,您需要将T约束为Eq

相关内容

  • 没有找到相关文章

最新更新