8

给定一个值列表,例如vec![0, 0, 1, 2],我想创建一个迭代器来生成其所有唯一排列。那是,

[0, 0, 1, 2]
[0, 0, 2, 1]
[0, 1, 0, 2]
[0, 1, 2, 0]
[0, 2, 0, 1]
[0, 2, 1, 0]
[1, 0, 0, 2]
[1, 0, 2, 0]
[1, 2, 0, 0]
[2, 0, 0, 1]
[2, 0, 1, 0]
[2, 1, 0, 0]

(请注意,有 12 种不同的排列,而如果我们有 4 个不同的元素,则将有 24 种不同的排列)。

已经有一种方法可以使用itertools 包生成排列(以及其他迭代器,如组合或没有替换的组合),但是对于排列,没有办法将排列限制为唯一的排列。

有一种相当有效的算法可以生成通常称为堆算法的排列,但是这没有考虑值的相等性/重复性。

这个问题在使用生成器的语言(例如 Python )中实现并不太棘手,但我觉得这在 Rust 中更棘手(至少与上面的解决方案相比),因为它需要使用迭代器(必须保持内部状态) ,或使用生成器(目前不稳定)。

4

3 回答 3

16

使用来自 itertools 的更多工具,即Itertools::unique

use itertools::Itertools; // 0.8.2

fn main() {
    let items = vec![0, 0, 1, 2];
    for perm in items.iter().permutations(items.len()).unique() {
        println!("{:?}", perm);
    }
}

也可以看看:

于 2020-01-28T03:28:25.847 回答
2

Python 解决方案可以转换为迭代器:

use std::collections::btree_set::{BTreeSet, IntoIter};

enum UniquePermutations {
    Leaf {
        elements: Option<Vec<i32>>,
    },
    Stem {
        elements: Vec<i32>,
        unique_elements: IntoIter<i32>,
        first_element: i32,
        inner: Box<Self>,
    },
}

impl UniquePermutations {
    fn new(elements: Vec<i32>) -> Self {
        if elements.len() == 1 {
            let elements = Some(elements);
            Self::Leaf { elements }
        } else {
            let mut unique_elements = elements
                .clone()
                .into_iter()
                .collect::<BTreeSet<_>>()
                .into_iter();

            let (first_element, inner) = Self::next_level(&mut unique_elements, elements.clone())
                .expect("Must have at least one item");

            Self::Stem {
                elements,
                unique_elements,
                first_element,
                inner,
            }
        }
    }

    fn next_level(
        mut unique_elements: impl Iterator<Item = i32>,
        elements: Vec<i32>,
    ) -> Option<(i32, Box<Self>)> {
        let first_element = unique_elements.next()?;

        let mut remaining_elements = elements;

        if let Some(idx) = remaining_elements.iter().position(|&i| i == first_element) {
            remaining_elements.remove(idx);
        }

        let inner = Box::new(Self::new(remaining_elements));

        Some((first_element, inner))
    }
}

impl Iterator for UniquePermutations {
    type Item = Vec<i32>;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Self::Leaf { elements } => elements.take(),
            Self::Stem {
                elements,
                unique_elements,
                first_element,
                inner,
            } => loop {
                match inner.next() {
                    Some(mut v) => {
                        v.insert(0, *first_element);
                        return Some(v);
                    }
                    None => {
                        let (next_fe, next_i) =
                            Self::next_level(&mut *unique_elements, elements.clone())?;
                        *first_element = next_fe;
                        *inner = next_i;
                    }
                }
            },
        }
    }
}

fn main() {
    let items = vec![0, 0, 1, 2];
    for perm in UniquePermutations::new(items) {
        println!("{:?}", perm);
    }
}

生成器解决方案隐藏了很多分配和复杂性,这在此处被带到了最前沿。调用堆栈变成了字段的链表inner,我们必须进行大量的克隆。

我没有执行任何微优化,例如使用 aVecDeque插入列表的头部,或者添加一个包装迭代器适配器,Vec在最终将其返回给调用者之前将其反转。我还用 aBTreeSet来专注于确保集合是独一无二的;随意将其更改为基于纯Vec的解决方案。

我也没有进行任何分析或基准测试。这可能会也可能不会更快。

crates.io 上有许多排列板条箱可用。我鼓励您查看是否可以将这段代码添加到其中的一个或多个中,以防止人们将来不得不解决这个问题。

于 2020-01-28T15:07:06.670 回答
0

如果您愿意放弃使用迭代器或生成器,则可以编写一个函数来输出列表的所有可能的唯一排列,代码如下。但是,由于即使在较小的情况下(例如,两个项目的向量),它也分配了很多向量,因此实现效率并不高。

fn unique_permutations<T: Clone>(items: Vec<T>) -> Vec<Vec<T>>
where
    T: Ord,
{
    if items.len() == 1 {
        vec![items]
    } else {
        let mut output: Vec<Vec<T>> = vec![];

        // Obtain a list of the unique elements.
        // Sorting and deduping should be faster than using a hashset for most small n.
        let mut unique_items = items.clone();
        unique_items.sort();
        unique_items.dedup();
        for first in unique_items {
            let mut remaining_elements = items.clone();

            // this feature is unstable
            // remaining_elements.remove_item(first);

            let index = remaining_elements.iter().position(|x| *x == first).unwrap();
            remaining_elements.remove(index);

            for mut permutation in unique_permutations(remaining_elements) {
                permutation.insert(0, first.clone());
                output.push(permutation);
            }
        }
        output
    }
}
于 2020-01-27T22:28:16.840 回答