Repository: rust-itertools/itertools (language: rust)

Issue:
add implementation of 5-tuple for tuple_combinations?
I was using tuple_combinations for iterating over various card combinations and ran into the 4-tuple limitation when trying to iterate over all possible 5-card combinations of a deck of 52 cards.  Any chance you'd add a five-tuple implementation or should I use another method?


Discussion / hints:

Fix patch:
diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs
index d98f6fe7c..167bc2c5f 100644
--- a/src/adaptors/mod.rs
+++ b/src/adaptors/mod.rs
@@ -806,9 +806,30 @@ macro_rules! impl_tuple_combination {
     )
 }
 
-impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a);
-impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b);
-impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c);
+// This snippet generates the twelve `impl_tuple_combination!` invocations:
+//    use core::iter;
+//    use itertools::Itertools;
+//
+//    for i in 2..=12 {
+//        println!("impl_tuple_combination!(Tuple{arity}Combination Tuple{prev}Combination; {tys}; {idents});",
+//            arity = i,
+//            prev = i - 1,
+//            tys = iter::repeat("A").take(i + 1).join(", "),
+//            idents = ('a'..'z').take(i - 1).join(" "),
+//        );
+//    }
+// It could probably be replaced by a bit more macro cleverness.
+impl_tuple_combination!(Tuple2Combination Tuple1Combination; A, A, A; a);
+impl_tuple_combination!(Tuple3Combination Tuple2Combination; A, A, A, A; a b);
+impl_tuple_combination!(Tuple4Combination Tuple3Combination; A, A, A, A, A; a b c);
+impl_tuple_combination!(Tuple5Combination Tuple4Combination; A, A, A, A, A, A; a b c d);
+impl_tuple_combination!(Tuple6Combination Tuple5Combination; A, A, A, A, A, A, A; a b c d e);
+impl_tuple_combination!(Tuple7Combination Tuple6Combination; A, A, A, A, A, A, A, A; a b c d e f);
+impl_tuple_combination!(Tuple8Combination Tuple7Combination; A, A, A, A, A, A, A, A, A; a b c d e f g);
+impl_tuple_combination!(Tuple9Combination Tuple8Combination; A, A, A, A, A, A, A, A, A, A; a b c d e f g h);
+impl_tuple_combination!(Tuple10Combination Tuple9Combination; A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i);
+impl_tuple_combination!(Tuple11Combination Tuple10Combination; A, A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i j);
+impl_tuple_combination!(Tuple12Combination Tuple11Combination; A, A, A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i j k);
 
 /// An iterator adapter to filter values within a nested `Result::Ok`.
 ///
diff --git a/src/cons_tuples_impl.rs b/src/cons_tuples_impl.rs
index 3cdfe0d18..5a1343891 100644
--- a/src/cons_tuples_impl.rs
+++ b/src/cons_tuples_impl.rs
@@ -35,7 +35,7 @@ macro_rules! impl_cons_iter(
     );
 );
 
-impl_cons_iter!(A, B, C, D, E, F, G, H,);
+impl_cons_iter!(A, B, C, D, E, F, G, H, I, J, K, L,);
 
 /// An iterator that maps an iterator of tuples like
 /// `((A, B), C)` to an iterator of `(A, B, C)`.
diff --git a/src/lib.rs b/src/lib.rs
index 1412930b1..e790889b7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1250,7 +1250,7 @@ pub trait Itertools : Iterator {
     /// elements from an iterator.
     ///
     /// Iterator element can be any homogeneous tuple of type `Self::Item` with
-    /// size up to 4.
+    /// size up to 12.
     ///
     /// ```
     /// use itertools::Itertools;
@@ -1485,7 +1485,7 @@ pub trait Itertools : Iterator {
 
     // non-adaptor methods
     /// Advances the iterator and returns the next items grouped in a tuple of
-    /// a specific size (up to 4).
+    /// a specific size (up to 12).
     ///
     /// If there are enough elements to be grouped in a tuple, then the tuple is
     /// returned inside `Some`, otherwise `None` is returned.
@@ -1505,7 +1505,7 @@ pub trait Itertools : Iterator {
     }
 
     /// Collects all items from the iterator into a tuple of a specific size
-    /// (up to 4).
+    /// (up to 12).
     ///
     /// If the number of elements inside the iterator is **exactly** equal to
     /// the tuple size, then the tuple is returned inside `Some`, otherwise
diff --git a/src/tuple_impl.rs b/src/tuple_impl.rs
index 4388e71e3..2af27953a 100644
--- a/src/tuple_impl.rs
+++ b/src/tuple_impl.rs
@@ -280,23 +280,14 @@ macro_rules! impl_tuple_collect {
                 return None;
             }
 
-            #[allow(unused_assignments)]
             fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                 where I: IntoIterator<Item = $A>
             {
                 let mut iter = iter.into_iter();
-                loop {
-                    $(
-                        let $Y = if let Some($Y) = iter.next() {
-                            $Y
-                        } else {
-                            break;
-                        };
-                    )*
-                    return Some(($($Y),*,))
-                }
 
-                return None;
+                Some(($(
+                    { let $Y = iter.next()?; $Y },
+                )*))
             }
 
             fn num_items() -> usize {
@@ -307,17 +298,37 @@ macro_rules! impl_tuple_collect {
                 use std::mem::replace;
 
                 let &mut ($(ref mut $Y),*,) = self;
-                let tmp = item;
                 $(
-                    let tmp = replace($Y_rev, tmp);
+                    let item = replace($Y_rev, item);
                 )*
-                drop(tmp);
+                drop(item);
             }
         }
     )
 }
 
+// This snippet generates the twelve `impl_tuple_collect!` invocations:
+//    use core::iter;
+//    use itertools::Itertools;
+//
+//    for i in 1..=12 {
+//        println!("impl_tuple_collect!({arity}; A; {ty}; {idents}; {rev_idents});",
+//            arity=i,
+//            ty=iter::repeat("A").take(i).join(", "),
+//            idents=('a'..='z').take(i).join(", "),
+//            rev_idents=('a'..='z').take(i).collect_vec().into_iter().rev().join(", ")
+//        );
+//    }
+// It could probably be replaced by a bit more macro cleverness.
 impl_tuple_collect!(1; A; A; a; a);
 impl_tuple_collect!(2; A; A, A; a, b; b, a);
 impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a);
 impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a);
+impl_tuple_collect!(5; A; A, A, A, A, A; a, b, c, d, e; e, d, c, b, a);
+impl_tuple_collect!(6; A; A, A, A, A, A, A; a, b, c, d, e, f; f, e, d, c, b, a);
+impl_tuple_collect!(7; A; A, A, A, A, A, A, A; a, b, c, d, e, f, g; g, f, e, d, c, b, a);
+impl_tuple_collect!(8; A; A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h; h, g, f, e, d, c, b, a);
+impl_tuple_collect!(9; A; A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i; i, h, g, f, e, d, c, b, a);
+impl_tuple_collect!(10; A; A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j; j, i, h, g, f, e, d, c, b, a);
+impl_tuple_collect!(11; A; A, A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j, k; k, j, i, h, g, f, e, d, c, b, a);
+impl_tuple_collect!(12; A; A, A, A, A, A, A, A, A, A, A, A, A; a, b, c, d, e, f, g, h, i, j, k, l; l, k, j, i, h, g, f, e, d, c, b, a);
diff --git a/src/ziptuple.rs b/src/ziptuple.rs
index 2dc3ea5e0..7a3000668 100644
--- a/src/ziptuple.rs
+++ b/src/ziptuple.rs
@@ -109,3 +109,7 @@ impl_zip_iter!(A, B, C, D, E);
 impl_zip_iter!(A, B, C, D, E, F);
 impl_zip_iter!(A, B, C, D, E, F, G);
 impl_zip_iter!(A, B, C, D, E, F, G, H);
+impl_zip_iter!(A, B, C, D, E, F, G, H, I);
+impl_zip_iter!(A, B, C, D, E, F, G, H, I, J);
+impl_zip_iter!(A, B, C, D, E, F, G, H, I, J, K);
+impl_zip_iter!(A, B, C, D, E, F, G, H, I, J, K, L);


Test patch: