/// Converts an iterator of tuples into a tuple of containers. /// /// `unzip()` consumes an entire iterator of n-ary tuples, producing `n` collections, one for each /// column. /// /// This function is, in some sense, the opposite of [`multizip`]. /// /// ``` /// use itertools::multiunzip; /// /// let inputs = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; /// /// let (a, b, c): (Vec<_>, Vec<_>, Vec<_>) = multiunzip(inputs); /// /// assert_eq!(a, vec![1, 4, 7]); /// assert_eq!(b, vec![2, 5, 8]); /// assert_eq!(c, vec![3, 6, 9]); /// ``` /// /// [`multizip`]: crate::multizip pub fn multiunzip(i: I) -> FromI where I: IntoIterator, I::IntoIter: MultiUnzip, { i.into_iter().multiunzip() } /// An iterator that can be unzipped into multiple collections. /// /// See [`.multiunzip()`](crate::Itertools::multiunzip) for more information. pub trait MultiUnzip: Iterator { /// Unzip this iterator into multiple collections. fn multiunzip(self) -> FromI; } macro_rules! impl_unzip_iter { ($($T:ident => $FromT:ident),*) => ( #[allow(non_snake_case)] impl, $($T, $FromT: Default + Extend<$T>),* > MultiUnzip<($($FromT,)*)> for IT { fn multiunzip(self) -> ($($FromT,)*) { // This implementation mirrors the logic of Iterator::unzip resp. Extend for (A, B) as close as possible. // Unfortunately a lot of the used api there is still unstable (https://github.com/rust-lang/rust/issues/72631). // // Iterator::unzip: https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#2825-2865 // Extend for (A, B): https://doc.rust-lang.org/src/core/iter/traits/collect.rs.html#370-411 let mut res = ($($FromT::default(),)*); let ($($FromT,)*) = &mut res; // Still unstable #72631 // let (lower_bound, _) = self.size_hint(); // if lower_bound > 0 { // $($FromT.extend_reserve(lower_bound);)* // } self.fold((), |(), ($($T,)*)| { // Still unstable #72631 // $( $FromT.extend_one($T); )* $( $FromT.extend(std::iter::once($T)); )* }); res } } ); } impl_unzip_iter!(); impl_unzip_iter!(A => FromA); impl_unzip_iter!(A => FromA, B => FromB); impl_unzip_iter!(A => FromA, B => FromB, C => FromC); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG, H => FromH); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG, H => FromH, I => FromI); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG, H => FromH, I => FromI, J => FromJ); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG, H => FromH, I => FromI, J => FromJ, K => FromK); impl_unzip_iter!(A => FromA, B => FromB, C => FromC, D => FromD, E => FromE, F => FromF, G => FromG, H => FromH, I => FromI, J => FromJ, K => FromK, L => FromL);