1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use std::error::Error;

/// Boxed static error type
pub type Err = Box<dyn Error + 'static>;

/// Takes a list where each element is a set of choices, and returns all the possible sets
/// generated. Will clone the elements.
///
/// ```
/// let v = vec![
///   vec![1],
///   vec![2, 3],
///   vec![4],
///   vec![5, 6, 7],
/// ];
///
/// assert_eq!(treebender::utils::combinations(&v), vec![
///   vec![1, 2, 4, 5],
///   vec![1, 3, 4, 5],
///   vec![1, 2, 4, 6],
///   vec![1, 3, 4, 6],
///   vec![1, 2, 4, 7],
///   vec![1, 3, 4, 7],
/// ]);
/// ```
pub fn combinations<T>(list: &[Vec<T>]) -> Vec<Vec<T>>
where
  T: Clone,
{
  if list.is_empty() {
    Vec::new()
  } else if list.len() == 1 {
    list[0].iter().map(|e| vec![e.clone()]).collect()
  } else {
    let (head, tail) = list.split_at(1);
    let head = &head[0];

    combinations(tail)
      .into_iter()
      .map(|subseq| {
        // prepend every element of the head to every possible subseq
        head.iter().map(move |v| {
          let mut newseq = subseq.clone();
          newseq.insert(0, v.clone());
          newseq
        })
      })
      .flatten()
      .collect()
  }
}