Itertools::group_by
is an iterator method that generates a new group every time the key function changes. The provided example shows how to use it with a for
loop, but using the output GroupBy
struct in an iterator chain seems to be very cumbersome, unless I misunderstood something:
let data = vec![1, 3, -2, -2, 1, 0, 1, 2];
// example from docs
for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) {
assert_eq!(4, group.sum::<i32>().abs());
}
// usage in an iterator method chain
data.iter()
.group_by(|elt| **elt >= 0)
.into_iter()
.map(|bool, group| (bool, group.collect::<Vec<i32>>()))
.collect::<Vec<(bool, Vec<i32>)>>();
The second example fails to compile:
error[E0619]: the type of this value must be known in this context
--> src/main.rs:16:35
|
16 | .map(|bool, group| (bool, group.collect::<Vec<i32>>()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0599]: no method named `collect` found for type `std::iter::Map<itertools::Groups<'_, bool, std::slice::Iter<'_, i32>, [closure@src/main.rs:14:19: 14:35]>, [closure@src/main.rs:16:14: 16:63]>` in the current scope
--> src/main.rs:17:10
|
17 | .collect::<Vec<(bool, Vec<i32>)>>();
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`std::iter::Map<itertools::Groups<'_, bool, std::slice::Iter<'_, i32>, [closure@src/main.rs:14:19: 14:35]>, [closure@src/main.rs:16:14: 16:63]> : std::iter::Iterator`
`&mut std::iter::Map<itertools::Groups<'_, bool, std::slice::Iter<'_, i32>, [closure@src/main.rs:14:19: 14:35]>, [closure@src/main.rs:16:14: 16:63]> : std::iter::Iterator`
error[E0593]: closure takes 2 arguments but 1 argument is required
--> src/main.rs:16:10
|
16 | .map(|bool, group| (bool, group.collect::<Vec<i32>>()))
| ^^^ ------------------------------------------------- takes 2 arguments
| |
| expected closure that takes 1 argument
I'm not confident I understand this error, but I think the compiler wants the closure's group
argument to have this explicit type:
itertools::Group<'_, bool, std::slice::Iter<'_, i32>, [closure@src\main.rs:26:15: 26:31]>
No one wants that in their code, so I hope I misunderstood.
The question is, whether it's possible, and how to use group_by
without a for loop?
The closure passed to map
has the wrong number of arguments (two instead of one: use a tuple instead); the error message is not very helpful of course :)
Also I wouldn't use bool
as a variable name, and you need to clone the integer references before you collect them (due to iter()
vs. into_iter()
).
Playground
extern crate itertools;
use itertools::Itertools;
fn main() {
let data = vec![1, 3, -2, -2, 1, 0, 1, 2];
let groups = data.iter()
.group_by(|elt| **elt >= 0)
.into_iter()
.map(|(ge0, group)| (ge0, group.cloned().collect()))
.collect::<Vec<(bool, Vec<i32>)>>();
println!("{:?}", groups);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With