Repository: rust-itertools/itertools (rust)

Issue:
`group_by` is weird
I spent several hours debugging my code written using the `group_by` function. 

I expected from this function the logic of grouping the same objects by a key, how surprised I was that he groups only some nearby elements while the group key has the same value.

In the documentation it is also indicated somehow strange and until the last, I was not sure if this is a bug or feature. I carefully read the documentation 5 times and it turned out to be a feature! Awful incomprehensible feature!

I do not think that this is the behavior that many expect for this method name. I demand to rename this method to something more suitable like `cons_group_by` or `lazy_group_by` not to mislead users.

[Example](https://play.integer32.com/?gist=09d53af6fff65075c756905d45400cf0&version=stable)

[I'm not the only one to think so](https://www.reddit.com/r/rust/comments/6d4no8/group_by_on_a_vect/di0j7tt/)

Pull request description:
Deprecate `group_by` in favor of `chunk_by`
Finally fixes #374 (see https://github.com/rust-itertools/itertools/issues/374#issuecomment-1917543782 and above for more details).

What do you think?
I'm not entirely sure of the documentation changes: when to use to term "chunk" and when to use "group".

I could additionally make "consecutive" bold.

Patch:
diff --git a/benches/bench1.rs b/benches/bench1.rs
index 8d88816..f718ce2 100644
--- a/benches/bench1.rs
+++ b/benches/bench1.rs
@@ -390,7 +390,7 @@ fn zip_unchecked_counted_loop3(c: &mut Criterion) {
     });
 }
 
-fn group_by_lazy_1(c: &mut Criterion) {
+fn chunk_by_lazy_1(c: &mut Criterion) {
     let mut data = vec![0; 1024];
     for (index, elt) in data.iter_mut().enumerate() {
         *elt = index / 10;
@@ -398,10 +398,10 @@ fn group_by_lazy_1(c: &mut Criterion) {
 
     let data = black_box(data);
 
-    c.bench_function("group by lazy 1", move |b| {
+    c.bench_function("chunk by lazy 1", move |b| {
         b.iter(|| {
-            for (_key, group) in &data.iter().group_by(|elt| **elt) {
-                for elt in group {
+            for (_key, chunk) in &data.iter().chunk_by(|elt| **elt) {
+                for elt in chunk {
                     black_box(elt);
                 }
             }
@@ -409,7 +409,7 @@ fn group_by_lazy_1(c: &mut Criterion) {
     });
 }
 
-fn group_by_lazy_2(c: &mut Criterion) {
+fn chunk_by_lazy_2(c: &mut Criterion) {
     let mut data = vec![0; 1024];
     for (index, elt) in data.iter_mut().enumerate() {
         *elt = index / 2;
@@ -417,10 +417,10 @@ fn group_by_lazy_2(c: &mut Criterion) {
 
     let data = black_box(data);
 
-    c.bench_function("group by lazy 2", move |b| {
+    c.bench_function("chunk by lazy 2", move |b| {
         b.iter(|| {
-            for (_key, group) in &data.iter().group_by(|elt| **elt) {
-                for elt in group {
+            for (_key, chunk) in &data.iter().chunk_by(|elt| **elt) {
+                for elt in chunk {
                     black_box(elt);
                 }
             }
@@ -436,8 +436,8 @@ fn slice_chunks(c: &mut Criterion) {
 
     c.bench_function("slice chunks", move |b| {
         b.iter(|| {
-            for group in data.chunks(sz) {
-                for elt in group {
+            for chunk in data.chunks(sz) {
+                for elt in chunk {
                     black_box(elt);
                 }
             }
@@ -453,8 +453,8 @@ fn chunks_lazy_1(c: &mut Criterion) {
 
     c.bench_function("chunks lazy 1", move |b| {
         b.iter(|| {
-            for group in &data.iter().chunks(sz) {
-                for elt in group {
+            for chunk in &data.iter().chunks(sz) {
+                for elt in chunk {
                     black_box(elt);
                 }
             }
@@ -813,8 +813,8 @@ criterion_group!(
     zipdot_i32_unchecked_counted_loop,
     zipdot_f32_unchecked_counted_loop,
     zip_unchecked_counted_loop3,
-    group_by_lazy_1,
-    group_by_lazy_2,
+    chunk_by_lazy_1,
+    chunk_by_lazy_2,
     slice_chunks,
     chunks_lazy_1,
     equal,
diff --git a/examples/iris.rs b/examples/iris.rs
index 5f55251..a041b28 100644
--- a/examples/iris.rs
+++ b/examples/iris.rs
@@ -77,15 +77,15 @@ fn main() {
     let mut plot_symbols = "+ox".chars().cycle();
     let mut symbolmap = HashMap::new();
 
-    // using Itertools::group_by
-    for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) {
+    // using Itertools::chunk_by
+    for (species, species_chunk) in &irises.iter().chunk_by(|iris| &iris.name) {
         // assign a plot symbol
         symbolmap
             .entry(species)
             .or_insert_with(|| plot_symbols.next().unwrap());
         println!("{} (symbol={})", species, symbolmap[species]);
 
-        for iris in species_group {
+        for iris in species_chunk {
             // using Itertools::format for lazy formatting
             println!("{:>3.1}", iris.data.iter().format(", "));
         }
diff --git a/src/groupbylazy.rs b/src/groupbylazy.rs
index c318ec7..007fea6 100644
--- a/src/groupbylazy.rs
+++ b/src/groupbylazy.rs
@@ -1,7 +1,7 @@
 use alloc::vec::{self, Vec};
 use std::cell::{Cell, RefCell};
 
-/// A trait to unify `FnMut` for `GroupBy` with the chunk key in `IntoChunks`
+/// A trait to unify `FnMut` for `ChunkBy` with the chunk key in `IntoChunks`
 trait KeyFunction<A> {
     type Key;
     fn call_mut(&mut self, arg: A) -> Self::Key;
@@ -282,10 +282,14 @@ where
     }
 }
 
-/// `GroupBy` is the storage for the lazy grouping operation.
+#[deprecated(note = "Use `ChunkBy` instead", since = "0.13.0")]
+/// See [`ChunkBy`](crate::structs::ChunkBy).
+pub type GroupBy<K, I, F> = ChunkBy<K, I, F>;
+
+/// `ChunkBy` is the storage for the lazy grouping operation.
 ///
 /// If the groups are consumed in their original order, or if each
-/// group is dropped without keeping it around, then `GroupBy` uses
+/// group is dropped without keeping it around, then `ChunkBy` uses
 /// no allocations. It needs allocations only if several group iterators
 /// are alive at the same time.
 ///
@@ -294,9 +298,9 @@ where
 /// value. It should be stored in a local variable or temporary and
 /// iterated.
 ///
-/// See [`.group_by()`](crate::Itertools::group_by) for more information.
+/// See [`.chunk_by()`](crate::Itertools::chunk_by) for more information.
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-pub struct GroupBy<K, I, F>
+pub struct ChunkBy<K, I, F>
 where
     I: Iterator,
 {
@@ -307,12 +311,12 @@ where
 }
 
 /// Create a new
-pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
+pub fn new<K, J, F>(iter: J, f: F) -> ChunkBy<K, J::IntoIter, F>
 where
     J: IntoIterator,
     F: FnMut(&J::Item) -> K,
 {
-    GroupBy {
+    ChunkBy {
         inner: RefCell::new(GroupInner {
             key: f,
             iter: iter.into_iter(),
@@ -329,7 +333,7 @@ where
     }
 }
 
-impl<K, I, F> GroupBy<K, I, F>
+impl<K, I, F> ChunkBy<K, I, F>
 where
     I: Iterator,
 {
@@ -348,7 +352,7 @@ where
     }
 }
 
-impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F>
+impl<'a, K, I, F> IntoIterator for &'a ChunkBy<K, I, F>
 where
     I: Iterator,
     I::Item: 'a,
@@ -368,7 +372,7 @@ where
 /// Iterator element type is `(K, Group)`:
 /// the group's key `K` and the group's iterator.
 ///
-/// See [`.group_by()`](crate::Itertools::group_by) for more information.
+/// See [`.chunk_by()`](crate::Itertools::chunk_by) for more information.
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 pub struct Groups<'a, K, I, F>
 where
@@ -377,7 +381,7 @@ where
     K: 'a,
     F: 'a,
 {
-    parent: &'a GroupBy<K, I, F>,
+    parent: &'a ChunkBy<K, I, F>,
 }
 
 impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
@@ -418,7 +422,7 @@ where
     K: 'a,
     F: 'a,
 {
-    parent: &'a GroupBy<K, I, F>,
+    parent: &'a ChunkBy<K, I, F>,
     index: usize,
     first: Option<I::Item>,
 }
@@ -476,7 +480,7 @@ where
 
 /// `ChunkLazy` is the storage for a lazy chunking operation.
 ///
-/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and
+/// `IntoChunks` behaves just like `ChunkBy`: it is iterable, and
 /// it only buffers if several chunk iterators are alive at the same time.
 ///
 /// This type implements [`IntoIterator`] (it is **not** an iterator
diff --git a/src/lib.rs b/src/lib.rs
index 1f39379..f12d95a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,7 @@
 //! - `use_std`
 //!   - Enabled by default.
 //!   - Disable to compile itertools using `#![no_std]`. This disables
-//!     any items that depend on collections (like `group_by`, `unique`,
+//!     any items that depend on collections (like `chunk_by`, `unique`,
 //!     `kmerge`, `join` and many more).
 //!
 //! ## Rust Version
@@ -99,8 +99,11 @@ pub mod structs {
     pub use crate::exactly_one_err::ExactlyOneError;
     pub use crate::flatten_ok::FlattenOk;
     pub use crate::format::{Format, FormatWith};
+    #[allow(deprecated)]
+    #[cfg(feature = "use_alloc")]
+    pub use crate::groupbylazy::GroupBy;
     #[cfg(feature = "use_alloc")]
-    pub use crate::groupbylazy::{Chunk, Chunks, Group, GroupBy, Groups, IntoChunks};
+    pub use crate::groupbylazy::{Chunk, ChunkBy, Chunks, Group, Groups, IntoChunks};
     #[cfg(feature = "use_std")]
     pub use crate::grouping_map::{GroupingMap, GroupingMapBy};
     pub use crate::intersperse::{Intersperse, IntersperseWith};
@@ -575,10 +578,10 @@ pub trait Itertools: Iterator {
     /// Consecutive elements that map to the same key (“runs”), are assigned
     /// to the same group.
     ///
-    /// `GroupBy` is the storage for the lazy grouping operation.
+    /// `ChunkBy` is the storage for the lazy grouping operation.
     ///
     /// If the groups are consumed in order, or if each group's iterator is
-    /// dropped without keeping it around, then `GroupBy` uses no
+    /// dropped without keeping it around, then `ChunkBy` uses no
     /// allocations.  It needs allocations only if several group iterators
     /// are alive at the same time.
     ///
@@ -593,20 +596,20 @@ pub trait Itertools: Iterator {
     /// ```
     /// use itertools::Itertools;
     ///
-    /// // group data into runs of larger than zero or not.
+    /// // chunk data into runs of larger than zero or not.
     /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2];
-    /// // groups:     |---->|------>|--------->|
+    /// // chunks:     |---->|------>|--------->|
     ///
-    /// // Note: The `&` is significant here, `GroupBy` is iterable
+    /// // Note: The `&` is significant here, `ChunkBy` is iterable
     /// // only by reference. You can also call `.into_iter()` explicitly.
     /// let mut data_grouped = Vec::new();
-    /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) {
-    ///     data_grouped.push((key, group.collect()));
+    /// for (key, chunk) in &data.into_iter().chunk_by(|elt| *elt >= 0) {
+    ///     data_grouped.push((key, chunk.collect()));
     /// }
     /// assert_eq!(data_grouped, vec![(true, vec![1, 3]), (false, vec![-2, -2]), (true, vec![1, 0, 1, 2])]);
     /// ```
     #[cfg(feature = "use_alloc")]
-    fn group_by<K, F>(self, key: F) -> GroupBy<K, Self, F>
+    fn chunk_by<K, F>(self, key: F) -> ChunkBy<K, Self, F>
     where
         Self: Sized,
         F: FnMut(&Self::Item) -> K,
@@ -615,13 +618,25 @@ pub trait Itertools: Iterator {
         groupbylazy::new(self, key)
     }
 
+    /// See [`.chunk_by()`](Itertools::chunk_by).
+    #[deprecated(note = "Use .chunk_by() instead", since = "0.13.0")]
+    #[cfg(feature = "use_alloc")]
+    fn group_by<K, F>(self, key: F) -> ChunkBy<K, Self, F>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item) -> K,
+        K: PartialEq,
+    {
+        self.chunk_by(key)
+    }
+
     /// Return an *iterable* that can chunk the iterator.
     ///
     /// Yield subiterators (chunks) that each yield a fixed number elements,
     /// determined by `size`. The last chunk will be shorter if there aren't
     /// enough elements.
     ///
-    /// `IntoChunks` is based on `GroupBy`: it is iterable (implements
+    /// `IntoChunks` is based on `ChunkBy`: it is iterable (implements
     /// `IntoIterator`, **not** `Iterator`), and it only buffers if several
     /// chunk iterators are alive at the same time.
     ///


Test patch:
diff --git a/tests/quick.rs b/tests/quick.rs
index 954655a..f96418f 100644
--- a/tests/quick.rs
+++ b/tests/quick.rs
@@ -1053,58 +1053,58 @@ quickcheck! {
 }
 
 quickcheck! {
-    fn fuzz_group_by_lazy_1(it: Iter<u8>) -> bool {
+    fn fuzz_chunk_by_lazy_1(it: Iter<u8>) -> bool {
         let jt = it.clone();
-        let groups = it.group_by(|k| *k);
-        itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x))
+        let chunks = it.chunk_by(|k| *k);
+        itertools::equal(jt, chunks.into_iter().flat_map(|(_, x)| x))
     }
 }
 
 quickcheck! {
-    fn fuzz_group_by_lazy_2(data: Vec<u8>) -> bool {
-        let groups = data.iter().group_by(|k| *k / 10);
-        let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
+    fn fuzz_chunk_by_lazy_2(data: Vec<u8>) -> bool {
+        let chunks = data.iter().chunk_by(|k| *k / 10);
+        let res = itertools::equal(data.iter(), chunks.into_iter().flat_map(|(_, x)| x));
         res
     }
 }
 
 quickcheck! {
-    fn fuzz_group_by_lazy_3(data: Vec<u8>) -> bool {
-        let grouper = data.iter().group_by(|k| *k / 10);
-        let groups = grouper.into_iter().collect_vec();
-        let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
+    fn fuzz_chunk_by_lazy_3(data: Vec<u8>) -> bool {
+        let grouper = data.iter().chunk_by(|k| *k / 10);
+        let chunks = grouper.into_iter().collect_vec();
+        let res = itertools::equal(data.iter(), chunks.into_iter().flat_map(|(_, x)| x));
         res
     }
 }
 
 quickcheck! {
-    fn fuzz_group_by_lazy_duo(data: Vec<u8>, order: Vec<(bool, bool)>) -> bool {
-        let grouper = data.iter().group_by(|k| *k / 3);
-        let mut groups1 = grouper.into_iter();
-        let mut groups2 = grouper.into_iter();
+    fn fuzz_chunk_by_lazy_duo(data: Vec<u8>, order: Vec<(bool, bool)>) -> bool {
+        let grouper = data.iter().chunk_by(|k| *k / 3);
+        let mut chunks1 = grouper.into_iter();
+        let mut chunks2 = grouper.into_iter();
         let mut elts = Vec::<&u8>::new();
-        let mut old_groups = Vec::new();
+        let mut old_chunks = Vec::new();
 
         let tup1 = |(_, b)| b;
         for &(ord, consume_now) in &order {
-            let iter = &mut [&mut groups1, &mut groups2][ord as usize];
+            let iter = &mut [&mut chunks1, &mut chunks2][ord as usize];
             match iter.next() {
                 Some((_, gr)) => if consume_now {
-                    for og in old_groups.drain(..) {
+                    for og in old_chunks.drain(..) {
                         elts.extend(og);
                     }
                     elts.extend(gr);
                 } else {
-                    old_groups.push(gr);
+                    old_chunks.push(gr);
                 },
                 None => break,
             }
         }
-        for og in old_groups.drain(..) {
+        for og in old_chunks.drain(..) {
             elts.extend(og);
         }
-        for gr in groups1.map(&tup1) { elts.extend(gr); }
-        for gr in groups2.map(&tup1) { elts.extend(gr); }
+        for gr in chunks1.map(&tup1) { elts.extend(gr); }
+        for gr in chunks2.map(&tup1) { elts.extend(gr); }
         itertools::assert_equal(&data, elts);
         true
     }
diff --git a/tests/test_std.rs b/tests/test_std.rs
index 5d28645..7266fdf 100644
--- a/tests/test_std.rs
+++ b/tests/test_std.rs
@@ -275,7 +275,7 @@ fn all_equal() {
     assert!("A".chars().all_equal());
     assert!(!"AABBCCC".chars().all_equal());
     assert!("AAAAAAA".chars().all_equal());
-    for (_key, mut sub) in &"AABBCCC".chars().group_by(|&x| x) {
+    for (_key, mut sub) in &"AABBCCC".chars().chunk_by(|&x| x) {
         assert!(sub.all_equal());
     }
 }
@@ -797,14 +797,14 @@ fn pad_using() {
 }
 
 #[test]
-fn group_by() {
-    for (ch1, sub) in &"AABBCCC".chars().group_by(|&x| x) {
+fn chunk_by() {
+    for (ch1, sub) in &"AABBCCC".chars().chunk_by(|&x| x) {
         for ch2 in sub {
             assert_eq!(ch1, ch2);
         }
     }
 
-    for (ch1, sub) in &"AAABBBCCCCDDDD".chars().group_by(|&x| x) {
+    for (ch1, sub) in &"AAABBBCCCCDDDD".chars().chunk_by(|&x| x) {
         for ch2 in sub {
             assert_eq!(ch1, ch2);
             if ch1 == 'C' {
@@ -817,8 +817,8 @@ fn group_by() {
 
     // try all possible orderings
     for indices in permutohedron::Heap::new(&mut [0, 1, 2, 3]) {
-        let groups = "AaaBbbccCcDDDD".chars().group_by(&toupper);
-        let mut subs = groups.into_iter().collect_vec();
+        let chunks = "AaaBbbccCcDDDD".chars().chunk_by(&toupper);
+        let mut subs = chunks.into_iter().collect_vec();
 
         for &idx in &indices[..] {
             let (key, text) = match idx {
@@ -833,8 +833,8 @@ fn group_by() {
         }
     }
 
-    let groups = "AAABBBCCCCDDDD".chars().group_by(|&x| x);
-    let mut subs = groups.into_iter().map(|(_, g)| g).collect_vec();
+    let chunks = "AAABBBCCCCDDDD".chars().chunk_by(|&x| x);
+    let mut subs = chunks.into_iter().map(|(_, g)| g).collect_vec();
 
     let sd = subs.pop().unwrap();
     let sc = subs.pop().unwrap();
@@ -851,7 +851,7 @@ fn group_by() {
     {
         let mut ntimes = 0;
         let text = "AABCCC";
-        for (_, sub) in &text.chars().group_by(|&x| {
+        for (_, sub) in &text.chars().chunk_by(|&x| {
             ntimes += 1;
             x
         }) {
@@ -863,7 +863,7 @@ fn group_by() {
     {
         let mut ntimes = 0;
         let text = "AABCCC";
-        for _ in &text.chars().group_by(|&x| {
+        for _ in &text.chars().chunk_by(|&x| {
             ntimes += 1;
             x
         }) {}
@@ -872,81 +872,80 @@ fn group_by() {
 
     {
         let text = "ABCCCDEEFGHIJJKK";
-        let gr = text.chars().group_by(|&x| x);
+        let gr = text.chars().chunk_by(|&x| x);
         it::assert_equal(gr.into_iter().flat_map(|(_, sub)| sub), text.chars());
     }
 }
 
 #[test]
-fn group_by_lazy_2() {
+fn chunk_by_lazy_2() {
     let data = [0, 1];
-    let groups = data.iter().group_by(|k| *k);
-    let gs = groups.into_iter().collect_vec();
+    let chunks = data.iter().chunk_by(|k| *k);
+    let gs = chunks.into_iter().collect_vec();
     it::assert_equal(data.iter(), gs.into_iter().flat_map(|(_k, g)| g));
 
     let data = [0, 1, 1, 0, 0];
-    let groups = data.iter().group_by(|k| *k);
-    let mut gs = groups.into_iter().collect_vec();
+    let chunks = data.iter().chunk_by(|k| *k);
+    let mut gs = chunks.into_iter().collect_vec();
     gs[1..].reverse();
     it::assert_equal(&[0, 0, 0, 1, 1], gs.into_iter().flat_map(|(_, g)| g));
 
-    let grouper = data.iter().group_by(|k| *k);
-    let mut groups = Vec::new();
-    for (k, group) in &grouper {
+    let grouper = data.iter().chunk_by(|k| *k);
+    let mut chunks = Vec::new();
+    for (k, chunk) in &grouper {
         if *k == 1 {
-            groups.push(group);
+            chunks.push(chunk);
         }
     }
-    it::assert_equal(&mut groups[0], &[1, 1]);
+    it::assert_equal(&mut chunks[0], &[1, 1]);
 
     let data = [0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3];
-    let grouper = data.iter().group_by(|k| *k);
-    let mut groups = Vec::new();
-    for (i, (_, group)) in grouper.into_iter().enumerate() {
+    let grouper = data.iter().chunk_by(|k| *k);
+    let mut chunks = Vec::new();
+    for (i, (_, chunk)) in grouper.into_iter().enumerate() {
         if i < 2 {
-            groups.push(group);
+            chunks.push(chunk);
         } else if i < 4 {
-            for _ in group {}
+            for _ in chunk {}
         } else {
-            groups.push(group);
+            chunks.push(chunk);
         }
     }
-    it::assert_equal(&mut groups[0], &[0, 0, 0]);
-    it::assert_equal(&mut groups[1], &[1, 1]);
-    it::assert_equal(&mut groups[2], &[3, 3]);
+    it::assert_equal(&mut chunks[0], &[0, 0, 0]);
+    it::assert_equal(&mut chunks[1], &[1, 1]);
+    it::assert_equal(&mut chunks[2], &[3, 3]);
 
-    // use groups as chunks
     let data = [0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3];
     let mut i = 0;
-    let grouper = data.iter().group_by(move |_| {
+    let grouper = data.iter().chunk_by(move |_| {
         let k = i / 3;
         i += 1;
         k
     });
-    for (i, group) in &grouper {
+    for (i, chunk) in &grouper {
         match i {
-            0 => it::assert_equal(group, &[0, 0, 0]),
-            1 => it::assert_equal(group, &[1, 1, 0]),
-            2 => it::assert_equal(group, &[0, 2, 2]),
-            3 => it::assert_equal(group, &[3, 3]),
+            0 => it::assert_equal(chunk, &[0, 0, 0]),
+            1 => it::assert_equal(chunk, &[1, 1, 0]),
+            2 => it::assert_equal(chunk, &[0, 2, 2]),
+            3 => it::assert_equal(chunk, &[3, 3]),
             _ => unreachable!(),
         }
     }
 }
 
 #[test]
-fn group_by_lazy_3() {
-    // test consuming each group on the lap after it was produced
+fn chunk_by_lazy_3() {
+    // test consuming each chunk on the lap after it was produced
     let data = [0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2];
-    let grouper = data.iter().group_by(|elt| *elt);
+    let grouper = data.iter().chunk_by(|elt| *elt);
     let mut last = None;
-    for (key, group) in &grouper {
+    for (key, chunk) in &grouper {
         if let Some(gr) = last.take() {
             for elt in gr {
                 assert!(elt != key && i32::abs(elt - key) == 1);
             }
         }
-        last = Some(group);
+        last = Some(chunk);
     }
 }