ndarray/itertools.rs
1// Copyright 2014-2019 bluss and ndarray developers
2// and MichaĆ Krasnoborski (krdln)
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! A few iterator-related utilities and tools
11
12use std::iter;
13
14/// Iterate `iterable` with a running index.
15///
16/// `IntoIterator` enabled version of `.enumerate()`.
17///
18/// ```
19/// use itertools::enumerate;
20///
21/// for (i, elt) in enumerate(&[1, 2, 3]) {
22/// /* loop body */
23/// }
24/// ```
25pub(crate) fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
26where
27 I: IntoIterator,
28{
29 iterable.into_iter().enumerate()
30}
31
32/// Iterate `i` and `j` in lock step.
33///
34/// `IntoIterator` enabled version of `i.zip(j)`.
35///
36/// ```
37/// use itertools::zip;
38///
39/// let data = [1, 2, 3, 4, 5];
40/// for (a, b) in zip(&data, &data[1..]) {
41/// /* loop body */
42/// }
43/// ```
44pub(crate) fn zip<I, J>(i: I, j: J) -> iter::Zip<I::IntoIter, J::IntoIter>
45where
46 I: IntoIterator,
47 J: IntoIterator,
48{
49 i.into_iter().zip(j)
50}
51
52/// Create an iterator running multiple iterators in lockstep.
53///
54/// The `izip!` iterator yields elements until any subiterator
55/// returns `None`.
56///
57/// This is a version of the standard ``.zip()`` that's supporting more than
58/// two iterators. The iterator element type is a tuple with one element
59/// from each of the input iterators. Just like ``.zip()``, the iteration stops
60/// when the shortest of the inputs reaches its end.
61///
62/// **Note:** The result of this macro is in the general case an iterator
63/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type.
64/// The special cases of one and two arguments produce the equivalent of
65/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively.
66///
67/// Prefer this macro `izip!()` over `multizip` for the performance benefits
68/// of using the standard library `.zip()`.
69///
70/// ```
71/// #[macro_use] extern crate itertools;
72/// # fn main() {
73///
74/// // iterate over three sequences side-by-side
75/// let mut results = [0, 0, 0, 0];
76/// let inputs = [3, 7, 9, 6];
77///
78/// for (r, index, input) in izip!(&mut results, 0..10, &inputs) {
79/// *r = index * 10 + input;
80/// }
81///
82/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
83/// # }
84/// ```
85///
86/// **Note:** To enable the macros in this crate, use the `#[macro_use]`
87/// attribute when importing the crate:
88///
89/// ```no_run
90/// # #[allow(unused_imports)]
91/// #[macro_use] extern crate itertools;
92/// # fn main() { }
93/// ```
94macro_rules! izip {
95 // @closure creates a tuple-flattening closure for .map() call. usage:
96 // @closure partial_pattern => partial_tuple , rest , of , iterators
97 // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee )
98 ( @closure $p:pat => $tup:expr ) => {
99 |$p| $tup
100 };
101
102 // The "b" identifier is a different identifier on each recursion level thanks to hygiene.
103 ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => {
104 izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*)
105 };
106
107 // unary
108 ($first:expr $(,)*) => {
109 IntoIterator::into_iter($first)
110 };
111
112 // binary
113 ($first:expr, $second:expr $(,)*) => {
114 izip!($first)
115 .zip($second)
116 };
117
118 // n-ary where n > 2
119 ( $first:expr $( , $rest:expr )* $(,)* ) => {
120 izip!($first)
121 $(
122 .zip($rest)
123 )*
124 .map(
125 izip!(@closure a => (a) $( , $rest )*)
126 )
127 };
128}