我有一个Vec<i64>,我想知道所有连续的整数组。举个例子:
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
Run Code Online (Sandbox Code Playgroud)
我期待这样或类似的事情:
[[1, 2, 3], [5, 6, 7], [9, 10]];
Run Code Online (Sandbox Code Playgroud)
视图(向量的向量或者元组或其他东西)真的无关紧要,但我应该得到几个具有连续数字的分组列表。
乍一看,似乎我需要使用 itertools 和该group_by函数,但我不知道如何...
小智 6
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
let mut res = Vec::new();
let mut prev = v[0];
let mut sub_v = Vec::new();
sub_v.push(prev);
for i in 1..v.len() {
if v[i] == prev + 1 {
sub_v.push(v[i]);
prev = v[i];
} else {
res.push(sub_v.clone());
sub_v.clear();
sub_v.push(v[i]);
prev = v[i];
}
}
res.push(sub_v);
Run Code Online (Sandbox Code Playgroud)
这应该可以解决你的问题。
迭代给定的向量,检查当前i64(在我的例子中i32)是否比前一个+1 i64,如果是,则将其推入向量(sub_v)。系列中断后,将 推sub_v入结果向量。重复。
但我猜你想要一些实用的东西?
您确实可以group_by用于此目的,但您可能并不真正想要。这是我可能会写的:
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
}
Run Code Online (Sandbox Code Playgroud)
这在原则上类似于 eXodiquas 的答案,但Vec<Vec<i64>>我没有累积 a ,而是使用索引来累积 aVec引用原始数据的切片引用。(这个问题解释了我为什么consecutive_slices要 take &[T]。)
Vec通过返回一个迭代器,也可以在不分配 a 的情况下做同样的事情;不过,我更喜欢上面的版本。这是我想出的零分配版本:
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
}
})
}
Run Code Online (Sandbox Code Playgroud)
它不像for循环那样可读,但它不需要Vec为返回值分配一个,所以这个版本更灵活。
这是一个“功能更强大”的版本,使用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()
}
Run Code Online (Sandbox Code Playgroud)
这个想法是制作一个关键函数,用于group_by获取每个元素与其在切片中的索引之间的差异。连续元素将具有相同的键,因为索引每次增加 1。我不喜欢这个版本的原因之一是很难获得原始数据结构的切片;您几乎必须创建一个Vec<Vec<i64>>(因此是两个collect)。另一个原因是我觉得读起来更难。
但是,当我第一次编写我喜欢的版本(第一个,带有for循环)时,它有一个错误(现已修复),而其他两个版本从一开始就是正确的。因此,即使对可读性和/或性能有一些影响,编写具有功能抽象的更密集代码也可能是有益的。