Skip to content

Commit aad1260

Browse files
committed
Implement Itertools::multiunzip
1 parent 20c09bd commit aad1260

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ pub use crate::repeatn::repeat_n;
179179
#[allow(deprecated)]
180180
pub use crate::sources::{repeat_call, unfold, iterate};
181181
pub use crate::with_position::Position;
182+
pub use crate::unziptuple::{multiunzip, MultiUnzip};
182183
pub use crate::ziptuple::multizip;
183184
mod adaptors;
184185
mod either_or_both;
@@ -237,6 +238,7 @@ mod tuple_impl;
237238
mod duplicates_impl;
238239
#[cfg(feature = "use_std")]
239240
mod unique_impl;
241+
mod unziptuple;
240242
mod with_position;
241243
mod zip_eq_impl;
242244
mod zip_longest;
@@ -3401,6 +3403,31 @@ pub trait Itertools : Iterator {
34013403
{
34023404
self.map(f).counts()
34033405
}
3406+
3407+
/// Unzips an iterator over tuples into a tuple of containers.
3408+
///
3409+
/// The first element of each tuple will be put into the first container, the second element into
3410+
/// the second, ....
3411+
///
3412+
/// It can be thought of as the reverse operation to [`Itertools::multiunzip`].
3413+
///
3414+
/// ```
3415+
/// use itertools::Itertools;
3416+
///
3417+
/// let inputs = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
3418+
///
3419+
/// let (a, b, c): (Vec<_>, Vec<_>, Vec<_>) = inputs
3420+
/// .into_iter()
3421+
/// .multiunzip();
3422+
///
3423+
/// assert_eq!((a, b, c), (vec![1, 4, 7], vec![2, 5, 8], vec![3, 6, 9]));
3424+
/// ```
3425+
fn multiunzip<FromI>(self) -> FromI
3426+
where
3427+
Self: Sized + MultiUnzip<FromI>,
3428+
{
3429+
MultiUnzip::multiunzip(self)
3430+
}
34043431
}
34053432

34063433
impl<T: ?Sized> Itertools for T where T: Iterator { }

src/unziptuple.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/// Unzips an iterator over tuples into a tuple of containers.
2+
///
3+
/// ```
4+
/// use itertools::multiunzip;
5+
///
6+
/// let inputs = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
7+
///
8+
/// let (a, b, c): (Vec<_>, Vec<_>, Vec<_>) = multiunzip(inputs);
9+
///
10+
/// assert_eq!((a, b, c), (vec![1, 4, 7], vec![2, 5, 8], vec![3, 6, 9]));
11+
/// ```
12+
pub fn multiunzip<FromI, I>(i: I) -> FromI
13+
where
14+
I: IntoIterator,
15+
I::IntoIter: MultiUnzip<FromI>,
16+
{
17+
i.into_iter().multiunzip()
18+
}
19+
20+
/// An iterator that can be unzipped into multiple collections.
21+
///
22+
/// See [`.multiunzip()`](crate::Itertools::multiunzip) for more information.
23+
pub trait MultiUnzip<FromI>: Iterator {
24+
/// Unzip this iterator into multiple collections.
25+
fn multiunzip(self) -> FromI;
26+
}
27+
28+
macro_rules! impl_unzip_iter {
29+
($($T:ident => $FromT:ident),*) => (
30+
impl_unzip_iter!(@rec $($T => $FromT,)*);
31+
);
32+
(@rec) => ();
33+
(@rec $__:ident => $___:ident, $($T:ident => $FromT:ident,)*) => (
34+
#[allow(non_snake_case)]
35+
impl<IT: Iterator<Item = ($($T,)*)>, $($T, $FromT: Default + Extend<$T>),* > MultiUnzip<($($FromT,)*)> for IT {
36+
fn multiunzip(self) -> ($($FromT,)*) {
37+
let mut res = ($($FromT::default(),)*);
38+
let ($($FromT,)*) = &mut res;
39+
40+
// Still unstable #72631
41+
// let (lower_bound, _) = self.size_hint();
42+
// if lower_bound > 0 {
43+
// $($FromT.extend_reserve(lower_bound);)*
44+
// }
45+
46+
self.fold((), |(), ($($T,)*)| {
47+
// Still unstable #72631
48+
// $( $FromT.extend_one($T); )*
49+
$( $FromT.extend(std::iter::once($T)); )*
50+
});
51+
res
52+
}
53+
}
54+
impl_unzip_iter!(@rec $($T => $FromT,)*);
55+
);
56+
}
57+
58+
impl_unzip_iter!(L => FromL, K => FromK, J => FromJ, I => FromI, H => FromH, G => FromG, F => FromF, E => FromE, D => FromD, C => FromC, B => FromB, A => FromA);

tests/test_std.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,3 +1080,9 @@ fn exactly_one_question_mark_return() -> Result<(), ExactlyOneError<std::slice::
10801080
[].iter().exactly_one()?;
10811081
Ok(())
10821082
}
1083+
1084+
#[test]
1085+
fn multiunzip() {
1086+
let (a, b, c): (Vec<_>, Vec<_>, Vec<_>) = [(0, 1, 2), (3, 4, 5), (6, 7, 8)].iter().cloned().multiunzip();
1087+
assert_eq!((a, b, c), (vec![0, 3, 6], vec![1, 4, 7], vec![2, 5, 8]));
1088+
}

0 commit comments

Comments
 (0)