如何知道所有切片元素是否相等,如果相等,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> {
// ... ?
}
我会使用 .all
:https://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])
}
}
.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"]));
}
我认为这是子切片模式的一个很好的用例:
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,
}
}
给定任何切片,例如:
let words = &["one", "one", "one", "two"];
如何知道所有元素是否相同?
更进一步,如果所有元素都相同,如何return引用第一个?
本质上,我正在尝试编写如下函数:
fn are_all_elements_equal<T>(elems: &[T]) -> Option<&T> {
// ... ?
}
我会使用 .all
:https://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])
}
}
.windows(2)
为您提供包含重叠元素对的迭代器。.all(|a| a[0] == a[1])
比较每个 window 中的两个元素
.then(|| &items[0])
returns 一个Option
包含对第一个元素的引用,如果前一个.all()
returnstrue
,否则它 returnsNone
match items.is_empty()
是必需的,因为如果切片为空,.all()
也会 returntrue
,这将导致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"]));
}
我认为这是子切片模式的一个很好的用例:
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,
}
}