我有一个Vec<i64>
,我想知道连续的所有整数组。举个例子:
let v = vec![1, 2, 3, 5, 6, 7, 9, 10];
我期待这样或类似的东西:
[[1, 2, 3], [5, 6, 7], [9, 10]];
视图(向量或可能是元组或其他东西的向量)确实无关紧要,但我应该得到几个连续数字的分组列表。
初看起来,似乎我需要使用itertools和group_by
函数,但我不知道如何......
答案 0 :(得分:4)
你确实可以使用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 slice_start > 0 {
result.push(&data[slice_start..]);
}
result
}
原则上类似于eXodiquas&#39;回答,但我没有累积Vec<Vec<i64>>
,而是使用索引来累积引用原始数据的Vec
切片引用。 (This question解释了我consecutive_slices
采取&[T]
的原因。)
通过返回迭代器,也可以在不分配Vec
的情况下做同样的事情;但是,我更喜欢上面的版本。这是我提出的零分配版本:
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
,因此这个版本更灵活。
更多的是为了好玩,而不是因为我认为这是一个好主意,这里的功能更强大了#34;版本使用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
)。另一个原因是我觉得很难读。如果嵌套的Vec
是您真正需要的,eXodiquas' answer可能是一个更好的起点。
答案 1 :(得分:2)
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);
这可以解决您的问题。
迭代给定的向量,检查当前i64
(在我的情况下为i32
)是否为前一个i64
+1,如果是,则将其推入向量({{ 1}})。系列断开后,将sub_v
推入结果向量。重复。
但我想你想要一些功能性的东西?
答案 2 :(得分:2)
另一种仅使用std的解决方案可能是:
fn consecutive_slices(v: &[i64]) -> Vec<Vec<i64>> {
let t: Vec<Vec<i64>> = v
.into_iter()
.chain([*v.last().unwrap_or(&-1)].iter())
.scan(Vec::new(), |s, &e| {
match s.last() {
None => { s.push(e); Some((false, Vec::new())) },
Some(&p) if p == e - 1 => { s.push(e); Some((false, Vec::new()))},
Some(&p) if p != e - 1 => {let o = s.clone(); *s = vec![e]; Some((true, o))},
_ => None,
}
})
.filter_map(|(n, v)| {
match n {
true => Some(v.clone()),
false => None,
}
})
.collect();
t
}
该链用于获取最后一个向量。