blob: a7744151c921db7ccbe038a4f81c14097a9721bc [file] [log] [blame]
use std::ops::Index;
use std::fmt;
/// An iterator to iterate through all the `n`-length combinations in an iterator.
///
/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Combinations<I: Iterator> {
n: usize,
indices: Vec<usize>,
pool: LazyBuffer<I>,
first: bool,
}
impl<I> fmt::Debug for Combinations<I>
where I: Iterator + fmt::Debug,
I::Item: fmt::Debug,
{
debug_fmt_fields!(Combinations, n, indices, pool, first);
}
/// Create a new `Combinations` from a clonable iterator.
pub fn combinations<I>(iter: I, n: usize) -> Combinations<I>
where I: Iterator
{
let mut indices: Vec<usize> = Vec::with_capacity(n);
for i in 0..n {
indices.push(i);
}
let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);
for _ in 0..n {
if !pool.get_next() {
break;
}
}
Combinations {
n: n,
indices: indices,
pool: pool,
first: true,
}
}
impl<I> Iterator for Combinations<I>
where I: Iterator,
I::Item: Clone
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
let mut pool_len = self.pool.len();
if self.pool.is_done() {
if pool_len == 0 || self.n > pool_len {
return None;
}
}
if self.first {
self.first = false;
} else if self.n == 0 {
return None;
} else {
// Scan from the end, looking for an index to increment
let mut i: usize = self.n - 1;
// Check if we need to consume more from the iterator
if self.indices[i] == pool_len - 1 && !self.pool.is_done() {
if self.pool.get_next() {
pool_len += 1;
}
}
while self.indices[i] == i + pool_len - self.n {
if i > 0 {
i -= 1;
} else {
// Reached the last combination
return None;
}
}
// Increment index, and reset the ones to its right
self.indices[i] += 1;
let mut j = i + 1;
while j < self.n {
self.indices[j] = self.indices[j - 1] + 1;
j += 1;
}
}
// Create result vector based on the indices
let mut result = Vec::with_capacity(self.n);
for i in self.indices.iter() {
result.push(self.pool[*i].clone());
}
Some(result)
}
}
#[derive(Debug)]
struct LazyBuffer<I: Iterator> {
it: I,
done: bool,
buffer: Vec<I::Item>,
}
impl<I> LazyBuffer<I>
where I: Iterator
{
pub fn new(it: I) -> LazyBuffer<I> {
let mut it = it;
let mut buffer = Vec::new();
let done;
if let Some(first) = it.next() {
buffer.push(first);
done = false;
} else {
done = true;
}
LazyBuffer {
it: it,
done: done,
buffer: buffer,
}
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_done(&self) -> bool {
self.done
}
pub fn get_next(&mut self) -> bool {
if self.done {
return false;
}
let next_item = self.it.next();
match next_item {
Some(x) => {
self.buffer.push(x);
true
}
None => {
self.done = true;
false
}
}
}
}
impl<I> Index<usize> for LazyBuffer<I>
where I: Iterator,
I::Item: Sized
{
type Output = I::Item;
fn index<'b>(&'b self, _index: usize) -> &'b I::Item {
self.buffer.index(_index)
}
}