Skip to content

Commit 80aa334

Browse files
committed
Adds .permutations(k) adaptor
1 parent a6e9713 commit 80aa334

9 files changed

+580
-53
lines changed

benches/bench1.rs

+43-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use test::{black_box};
77
use itertools::Itertools;
88

99
use itertools::free::cloned;
10+
use itertools::Permutations;
1011

1112
use std::iter::repeat;
1213
use std::cmp;
13-
use std::ops::Add;
14+
use std::ops::{Add, Range};
1415

1516
mod extra;
1617

@@ -762,3 +763,44 @@ fn all_equal_default(b: &mut test::Bencher) {
762763

763764
b.iter(|| xs.iter().dedup().nth(1).is_none())
764765
}
766+
767+
const PERM_COUNT: usize = 6;
768+
769+
#[bench]
770+
fn permutations_iter(b: &mut test::Bencher) {
771+
struct NewIterator(Range<usize>);
772+
773+
impl Iterator for NewIterator {
774+
type Item = usize;
775+
776+
fn next(&mut self) -> Option<Self::Item> {
777+
self.0.next()
778+
}
779+
}
780+
781+
b.iter(|| {
782+
for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) {
783+
784+
}
785+
})
786+
}
787+
788+
#[bench]
789+
fn permutations_range(b: &mut test::Bencher) {
790+
b.iter(|| {
791+
for _ in (0..PERM_COUNT).permutations(PERM_COUNT) {
792+
793+
}
794+
})
795+
}
796+
797+
#[bench]
798+
fn permutations_slice(b: &mut test::Bencher) {
799+
let v = (0..PERM_COUNT).collect_vec();
800+
801+
b.iter(|| {
802+
for _ in v.as_slice().iter().permutations(PERM_COUNT) {
803+
804+
}
805+
})
806+
}

src/combinations.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use std::fmt;
22

33
use super::lazy_buffer::LazyBuffer;
44

5-
/// An iterator to iterate through all the `n`-length combinations in an iterator.
5+
/// An iterator to iterate through all the `k`-length combinations in an iterator.
66
///
77
/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
88
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
99
pub struct Combinations<I: Iterator> {
10-
n: usize,
10+
k: usize,
1111
indices: Vec<usize>,
1212
pool: LazyBuffer<I>,
1313
first: bool,
@@ -17,27 +17,27 @@ impl<I> fmt::Debug for Combinations<I>
1717
where I: Iterator + fmt::Debug,
1818
I::Item: fmt::Debug,
1919
{
20-
debug_fmt_fields!(Combinations, n, indices, pool, first);
20+
debug_fmt_fields!(Combinations, k, indices, pool, first);
2121
}
2222

2323
/// Create a new `Combinations` from a clonable iterator.
24-
pub fn combinations<I>(iter: I, n: usize) -> Combinations<I>
24+
pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
2525
where I: Iterator
2626
{
27-
let mut indices: Vec<usize> = Vec::with_capacity(n);
28-
for i in 0..n {
27+
let mut indices: Vec<usize> = Vec::with_capacity(k);
28+
for i in 0..k {
2929
indices.push(i);
3030
}
3131
let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);
3232

33-
for _ in 0..n {
33+
for _ in 0..k {
3434
if !pool.get_next() {
3535
break;
3636
}
3737
}
3838

3939
Combinations {
40-
n: n,
40+
k: k,
4141
indices: indices,
4242
pool: pool,
4343
first: true,
@@ -52,18 +52,18 @@ impl<I> Iterator for Combinations<I>
5252
fn next(&mut self) -> Option<Self::Item> {
5353
let mut pool_len = self.pool.len();
5454
if self.pool.is_done() {
55-
if pool_len == 0 || self.n > pool_len {
55+
if pool_len == 0 || self.k > pool_len {
5656
return None;
5757
}
5858
}
5959

6060
if self.first {
6161
self.first = false;
62-
} else if self.n == 0 {
62+
} else if self.k == 0 {
6363
return None;
6464
} else {
6565
// Scan from the end, looking for an index to increment
66-
let mut i: usize = self.n - 1;
66+
let mut i: usize = self.k - 1;
6767

6868
// Check if we need to consume more from the iterator
6969
if self.indices[i] == pool_len - 1 && !self.pool.is_done() {
@@ -72,7 +72,7 @@ impl<I> Iterator for Combinations<I>
7272
}
7373
}
7474

75-
while self.indices[i] == i + pool_len - self.n {
75+
while self.indices[i] == i + pool_len - self.k {
7676
if i > 0 {
7777
i -= 1;
7878
} else {
@@ -84,14 +84,14 @@ impl<I> Iterator for Combinations<I>
8484
// Increment index, and reset the ones to its right
8585
self.indices[i] += 1;
8686
let mut j = i + 1;
87-
while j < self.n {
87+
while j < self.k {
8888
self.indices[j] = self.indices[j - 1] + 1;
8989
j += 1;
9090
}
9191
}
9292

9393
// Create result vector based on the indices
94-
let mut result = Vec::with_capacity(self.n);
94+
let mut result = Vec::with_capacity(self.k);
9595
for i in self.indices.iter() {
9696
result.push(self.pool[*i].clone());
9797
}

src/combinations_with_replacement.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ where
1111
I: Iterator,
1212
I::Item: Clone,
1313
{
14-
n: usize,
14+
k: usize,
1515
indices: Vec<usize>,
1616
// The current known max index value. This increases as pool grows.
1717
max_index: usize,
@@ -24,7 +24,7 @@ where
2424
I: Iterator + fmt::Debug,
2525
I::Item: fmt::Debug + Clone,
2626
{
27-
debug_fmt_fields!(Combinations, n, indices, max_index, pool, first);
27+
debug_fmt_fields!(Combinations, k, indices, max_index, pool, first);
2828
}
2929

3030
impl<I> CombinationsWithReplacement<I>
@@ -39,16 +39,16 @@ where
3939
}
4040

4141
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
42-
pub fn combinations_with_replacement<I>(iter: I, n: usize) -> CombinationsWithReplacement<I>
42+
pub fn combinations_with_replacement<I>(iter: I, k: usize) -> CombinationsWithReplacement<I>
4343
where
4444
I: Iterator,
4545
I::Item: Clone,
4646
{
47-
let indices: Vec<usize> = vec![0; n];
47+
let indices: Vec<usize> = vec![0; k];
4848
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
4949

5050
CombinationsWithReplacement {
51-
n,
51+
k,
5252
indices,
5353
max_index: 0,
5454
pool: pool,
@@ -66,7 +66,7 @@ where
6666
// If this is the first iteration, return early
6767
if self.first {
6868
// In empty edge cases, stop iterating immediately
69-
return if self.n == 0 || self.pool.is_done() {
69+
return if self.k == 0 || self.pool.is_done() {
7070
None
7171
// Otherwise, yield the initial state
7272
} else {

src/lazy_buffer.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Index;
22

33
#[derive(Debug, Clone)]
44
pub struct LazyBuffer<I: Iterator> {
5-
it: I,
5+
pub it: I,
66
done: bool,
77
buffer: Vec<I::Item>,
88
}
@@ -54,14 +54,15 @@ where
5454
}
5555
}
5656

57-
impl<I> Index<usize> for LazyBuffer<I>
57+
impl<I, J> Index<J> for LazyBuffer<I>
5858
where
5959
I: Iterator,
6060
I::Item: Sized,
61+
Vec<I::Item>: Index<J>
6162
{
62-
type Output = I::Item;
63+
type Output = <Vec<I::Item> as Index<J>>::Output;
6364

64-
fn index<'b>(&'b self, _index: usize) -> &'b I::Item {
65+
fn index(&self, _index: J) -> &Self::Output {
6566
self.buffer.index(_index)
6667
}
6768
}

src/lib.rs

+70-15
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ pub mod structs {
117117
pub use multipeek_impl::MultiPeek;
118118
pub use pad_tail::PadUsing;
119119
pub use peeking_take_while::PeekingTakeWhile;
120+
#[cfg(feature = "use_std")]
121+
pub use permutations::Permutations;
120122
pub use process_results_impl::ProcessResults;
121123
#[cfg(feature = "use_std")]
122124
pub use put_back_n_impl::PutBackN;
@@ -182,6 +184,8 @@ mod minmax;
182184
mod multipeek_impl;
183185
mod pad_tail;
184186
mod peeking_take_while;
187+
#[cfg(feature = "use_std")]
188+
mod permutations;
185189
mod process_results_impl;
186190
#[cfg(feature = "use_std")]
187191
mod put_back_n_impl;
@@ -1135,12 +1139,15 @@ pub trait Itertools : Iterator {
11351139
adaptors::tuple_combinations(self)
11361140
}
11371141

1138-
/// Return an iterator adaptor that iterates over the `n`-length combinations of
1142+
/// Return an iterator adaptor that iterates over the `k`-length combinations of
11391143
/// the elements from an iterator.
11401144
///
11411145
/// Iterator element type is `Vec<Self::Item>`. The iterator produces a new Vec per iteration,
11421146
/// and clones the iterator elements.
11431147
///
1148+
/// If the input iterator is empty, or `k` is 0, or `k` greater than the
1149+
/// length of the input iterator, the resultant iterator adaptor will be empty.
1150+
///
11441151
/// ```
11451152
/// use itertools::Itertools;
11461153
///
@@ -1150,10 +1157,11 @@ pub trait Itertools : Iterator {
11501157
/// vec![1, 2, 4],
11511158
/// vec![1, 3, 4],
11521159
/// vec![2, 3, 4],
1153-
/// ]);
1160+
/// ]);
11541161
/// ```
11551162
///
11561163
/// Note: Combinations does not take into account the equality of the iterated values.
1164+
///
11571165
/// ```
11581166
/// use itertools::Itertools;
11591167
///
@@ -1164,16 +1172,15 @@ pub trait Itertools : Iterator {
11641172
/// vec![2, 2],
11651173
/// ]);
11661174
/// ```
1167-
///
11681175
#[cfg(feature = "use_std")]
1169-
fn combinations(self, n: usize) -> Combinations<Self>
1176+
fn combinations(self, k: usize) -> Combinations<Self>
11701177
where Self: Sized,
11711178
Self::Item: Clone
11721179
{
1173-
combinations::combinations(self, n)
1180+
combinations::combinations(self, k)
11741181
}
11751182

1176-
/// Return an iterator that iterates over the `n`-length combinations of
1183+
/// Return an iterator that iterates over the `k`-length combinations of
11771184
/// the elements from an iterator, with replacement.
11781185
///
11791186
/// Iterator element type is `Vec<Self::Item>`. The iterator produces a new Vec per iteration,
@@ -1190,15 +1197,61 @@ pub trait Itertools : Iterator {
11901197
/// vec![2, 2],
11911198
/// vec![2, 3],
11921199
/// vec![3, 3],
1193-
/// ]);
1200+
/// ]);
11941201
/// ```
11951202
#[cfg(feature = "use_std")]
1196-
fn combinations_with_replacement(self, n: usize) -> CombinationsWithReplacement<Self>
1203+
fn combinations_with_replacement(self, k: usize) -> CombinationsWithReplacement<Self>
11971204
where
11981205
Self: Sized,
11991206
Self::Item: Clone,
12001207
{
1201-
combinations_with_replacement::combinations_with_replacement(self, n)
1208+
combinations_with_replacement::combinations_with_replacement(self, k)
1209+
}
1210+
1211+
/// Return an iterator adaptor that iterates over all k-permutations of the
1212+
/// elements from an iterator.
1213+
///
1214+
/// Iterator element type is `Vec<Self::Item>` with length `k`. The iterator
1215+
/// produces a new Vec per iteration, and clones the iterator elements.
1216+
///
1217+
/// If `k` is greater than the length of the input iterator, the resultant
1218+
/// iterator adaptor will be empty.
1219+
///
1220+
/// ```
1221+
/// use itertools::Itertools;
1222+
///
1223+
/// let perms = (5..8).permutations(2);
1224+
/// itertools::assert_equal(perms, vec![
1225+
/// vec![5, 6],
1226+
/// vec![5, 7],
1227+
/// vec![6, 5],
1228+
/// vec![6, 7],
1229+
/// vec![7, 5],
1230+
/// vec![7, 6],
1231+
/// ]);
1232+
/// ```
1233+
///
1234+
/// Note: Permutations does not take into account the equality of the iterated values.
1235+
///
1236+
/// ```
1237+
/// use itertools::Itertools;
1238+
///
1239+
/// let it = vec![2, 2].into_iter().permutations(2);
1240+
/// itertools::assert_equal(it, vec![
1241+
/// vec![2, 2], // Note: these are the same
1242+
/// vec![2, 2], // Note: these are the same
1243+
/// ]);
1244+
///
1245+
/// Note: The source iterator is collected lazily, and will not be
1246+
/// re-iterated if the permutations adaptor is completed and re-iterated.
1247+
/// ```
1248+
///
1249+
#[cfg(feature = "use_std")]
1250+
fn permutations(self, k: usize) -> Permutations<Self>
1251+
where Self: Sized,
1252+
Self::Item: Clone
1253+
{
1254+
permutations::permutations(self, k)
12021255
}
12031256

12041257
/// Return an iterator adaptor that pads the sequence to a minimum length of
@@ -1997,19 +2050,21 @@ pub trait Itertools : Iterator {
19972050
/// assert_eq!(successes, [1, 2]);
19982051
/// assert_eq!(failures, [false, true]);
19992052
/// ```
2000-
fn partition_map<A, B, F, L, R>(self, mut predicate: F) -> (A, B)
2053+
fn partition_map<A, B, F, L, R>(self, predicate: F) -> (A, B)
20012054
where Self: Sized,
2002-
F: FnMut(Self::Item) -> Either<L, R>,
2055+
F: Fn(Self::Item) -> Either<L, R>,
20032056
A: Default + Extend<L>,
20042057
B: Default + Extend<R>,
20052058
{
20062059
let mut left = A::default();
20072060
let mut right = B::default();
20082061

2009-
self.for_each(|val| match predicate(val) {
2010-
Either::Left(v) => left.extend(Some(v)),
2011-
Either::Right(v) => right.extend(Some(v)),
2012-
});
2062+
for val in self {
2063+
match predicate(val) {
2064+
Either::Left(v) => left.extend(Some(v)),
2065+
Either::Right(v) => right.extend(Some(v)),
2066+
}
2067+
}
20132068

20142069
(left, right)
20152070
}

0 commit comments

Comments
 (0)