如何迭代包含相等元素的切片的连续子序列?

How do you iterate over continuous subsequences of a slice that contain equal elements?

提问人:RBF06 提问时间:9/16/2023 最后编辑:cafce25RBF06 更新时间:9/17/2023 访问量:50

问:

我有一个在切片中实现的类型的元素序列。为了说明这一点,假设它看起来像这样:PartialEq

let data = [1,1,1,2,2,3,4,5,5,5,5,6];

我想迭代这个序列的借用切片,以便这些切片的所有元素都相等。例如,在上面的切片中,我想要一个迭代器,它产生:PartialEqdata

&data[0..3]   // [1,1,1]
&data[3..5]   // [2,2]
&data[5..6]   // [3]
&data[6..7]   // [4]
&data[7..11]  // [5,5,5,5]
&data[11..12] // [6]

看起来 slice::group_by 正是我需要的,但从 Rust 1.72.0 开始,它还不稳定。有没有直接的方法可以以稳定的方式获得此功能,无论是通过使用第三方 crate 还是结合使用稳定的 std lib API?

Rust 迭代器 切片

评论

1赞 harmic 9/16/2023
你可以从 itertools crate 中使用group_by

答:

5赞 drewtato 9/16/2023 #1

group_by是一个非常简单的函数。它返回一个迭代器,其中包含以下实现:next

fn next(&mut self) -> Option<Self::Item> {
    if self.slice.is_empty() {
        None
    } else {
        let mut len = 1;
        let mut iter = self.slice.windows(2);
        while let Some([l, r]) = iter.next() {
            if (self.predicate)(l, r) { len += 1 } else { break }
        }
        let (head, tail) = self.slice.split_at(len);
        self.slice = tail;
        Some(head)
    }
}

由于你有一个简单的谓词,你可以用更短的from_fn制作一个迭代器。

fn group_by<T: PartialEq>(mut slice: &[T]) -> impl Iterator<Item = &[T]> + '_ {
    std::iter::from_fn(move || {
        let first = slice.first()?;
        let len = slice.iter().position(|t| first != t).unwrap_or(slice.len());
        let (head, tail) = slice.split_at(len);
        slice = tail;
        Some(head)
    })
}

这与调用之间的唯一区别是,这个元素检查与第一个元素的相等性,这可能会为非类型提供不同的结果。如果这对您很重要,您可以从每晚返回该方法。group_by(|a, b| a == b)Eqwindowsgroup_by

1赞 user4815162342 9/17/2023 #2

如果你不需要子组作为切片,而是作为可迭代的东西,你可以从 itertools crate 中使用 Itertools::group_by():

let data = [1, 1, 1, 2, 2, 3, 4, 5, 5, 5, 5, 6];

for (_k, group) in &data.iter().group_by(|&k| k) {
    println!("{:?}", group.collect_vec());
}

如果不同时保留同一迭代器中的多个组,则不会分配该对象。group

平台