如何在Rust中将向量中的连续整数分组? [英] How can I group consecutive integers in a vector in Rust?

查看:61
本文介绍了如何在Rust中将向量中的连续整数分组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Vec< i64> ,我想知道所有连续的整数组.例如:

I have a Vec<i64> and I want to know all the groups of integers that are consecutive. As an example:

let v = vec![1, 2, 3, 5, 6, 7, 9, 10];

我期望像这样或类似的东西:

I'm expecting something like this or similar:

[[1, 2, 3], [5, 6, 7], [9, 10]];

视图(向量或元组或其他元素的向量)的确无关紧要,但是我应该得到几个具有连续数字的分组列表.

The view (vector of vectors or maybe tuples or something else) really doesn't matter, but I should get several grouped lists with continuous numbers.

乍看之下,似乎我需要使用itertools和 group_by 函数,但是我不知道如何...

At the first look, it seems like I'll need to use itertools and the group_by function, but I have no idea how...

推荐答案

确实可以为此使用 group_by ,但是您可能并不是真的想要.这可能是我可能写的:

You can indeed use group_by for this, but you might not really want to. Here's what I would probably write instead:

fn consecutive_slices(data: &[i64]) -> Vec<&[i64]> {
    let mut slice_start = 0;
    let mut result = Vec::new();
    for i in 1..data.len() {
        if data[i - 1] + 1 != data[i] {
            result.push(&data[slice_start..i]);
            slice_start = i;
        }
    }
    if data.len() > 0 {
        result.push(&data[slice_start..]);
    }
    result
}

这在原理上与eXodiquas的答案相似,但是我不是使用累积 Vec< Vec< i64>> 的方法,而是使用索引累积了引用原始数据的切片引用.(这个问题解释了为什么我让 conecutive_slices 取为& [T] .)

This is similar in principle to eXodiquas' answer, but instead of accumulating a Vec<Vec<i64>>, I use the indices to accumulate a Vec of slice references that refer to the original data. (This question explains why I made consecutive_slices take &[T].)

通过返回一个迭代器,也可以在不分配 Vec 的情况下执行相同的操作;但是,我更喜欢上面的版本.这是我想出的零分配版本:

It's also possible to do the same thing without allocating a Vec, by returning an iterator; however, I like the above version better. Here's the zero-allocation version I came up with:

fn consecutive_slices(data: &[i64]) -> impl Iterator<Item = &[i64]> {
    let mut slice_start = 0;
    (1..data.len() + 1).flat_map(move |i| {
        if i == data.len() || data[i - 1] + 1 != data[i] {
            let begin = slice_start;
            slice_start = i;
            Some(&data[begin..i])
        } else {
            None
        }
    })
}

它的可读性不如 for 循环,但不需要为返回值分配 Vec ,因此此版本更加灵活.

It's not as readable as a for loop, but it doesn't need to allocate a Vec for the return value, so this version is more flexible.

这是使用 group_by 的更实用"的版本:

Here's a "more functional" version using group_by:

use itertools::Itertools;

fn consecutive_slices(data: &[i64]) -> Vec<Vec<i64>> {
    (&(0..data.len()).group_by(|&i| data[i] as usize - i))
        .into_iter()
        .map(|(_, group)| group.map(|i| data[i]).collect())
        .collect()
}

这个想法是为 group_by 创建一个关键函数,该函数可以获取每个元素及其在切片中的索引之间的差异.连续元素将具有相同的键,因为索引每次都增加1.我不喜欢此版本的原因之一是很难获得原始数据结构的片段.您几乎必须创建一个 Vec< Vec< i64>> (因此这两个 collect ).另一个原因是我觉得很难阅读.

The idea is to make a key function for group_by that takes the difference between each element and its index in the slice. Consecutive elements will have the same key because indices increase by 1 each time. One reason I don't like this version is that it's quite difficult to get slices of the original data structure; you almost have to create a Vec<Vec<i64>> (hence the two collects). The other reason is that I find it harder to read.

但是,当我第一次编写自己的首选版本(第一个版本,带有 for 循环)时,它存在一个错误(现已修复),而其他两个版本从一开始都是正确的.因此,即使对可读性和/或性能有一定的影响,使用功能抽象编写更密集的代码还是有好处的.

However, when I first wrote my preferred version (the first one, with the for loop), it had a bug (now fixed), while the other two versions were correct from the start. So there may be merit to writing denser code with functional abstractions, even if there is some hit to readability and/or performance.

这篇关于如何在Rust中将向量中的连续整数分组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆