【问题标题】:Fastest way to check if atleast one element is in a collection检查集合中是否至少有一个元素的最快方法
【发布时间】:2023-02-04 09:10:40
【问题描述】:

我曾经遇到过 python 的问题,我必须检查集合中的至少一个项目是否与集合列表中的所有单个集合相交。

所以例如我有三个集合:

A = [
{"a", "b", "c"},
{"c", "d", "e"},
{"a", "l", "k"}
]

和一个独特的字符集合 U:

U = {"a", "b", "c", "d", "e", "l", "k"}

我现在想找到 U 的最短组合,其中至少一个字符出现在 A 的所有集合中。

例如组合 ["a", "c"] 将是一个解决方案。 ["a", "d"], ["a", "e"] 也可以,我想把它们都找出来,以便以后找到一个最佳的(每个字符都有一些特征)。

我在 python 中写这个的方式如下:

for i in range(1,5):
    combs = itertools.combinations(U, i)
    for c in combs:
        if all(set(c) & l for l in A):
            # -> solution found

因为它可能有一个很大的 A 和 U 列表,可能的组合数量可能会变成天文数字,所以我尝试用 Rust 实现它,但是我的 Rust 实现与 Python 一样“慢”。

// the input is a bit weird, but this step doesnt take much time i times
let A: Vec<HashSet<String>> = A.into_iter().map(|x| HashSet::from_iter(x)).collect();

let mut possible = vec![];

for n_combs in 1..=4 {
    for i in U.iter().combinations(n_combs) {
        let outp = A.iter().fold(0, |acc, x| {
            for j in i.iter() {
                if x.contains(*j) {
                    return acc + 1;
                }
            }
            acc
        });


        if outp == A.len() {
            //solution

        }
    }

我将这两个示例都运行到迭代部分并且速度相同。所以问题是我如何检查交叉点。 感谢您对改进这一点的任何帮助,谢谢

【问题讨论】:

  • 对于 Rust 实现,您在编译时是否使用了 --release 标志?
  • 是的,我使用了 --release .. 没有它必须比 python 版本慢
  • 我认为组合的使用会在这里扼杀它,但我需要更多地考虑如何摆脱搜索所有这些序列
  • 即使组合不是正确的方法,我仍然很好奇与 Rust 相比,Python 的检查速度如此之快。我认为我所做的远非最佳
  • 我怀疑您通过进行一组额外的迭代大大增加了时间复杂度,但我的生锈并不好

标签: python rust


【解决方案1】:

很难说没有完整的可重现示例,但我认为使用BTreeSets、is_disjointany 可能是可行的方法。例如。就像是:

let A: Vec<BTreeSet<String>> = A.into_iter().map(|x| BTreeSet::from_iter(x)).collect();

let mut possible = vec![];

for n_combs in 1..=4 {
    for i in U.iter().combinations(n_combs) {
        let i = BTreeSet::from_iter (i.into_iter());
        if !A.iter().any (|a| a.is_disjoint (&i)) {
           //solution
        }
    }
}

【讨论】:

  • 在您的示例中,i 的类型是 BTreeSet<&String>,但是 A 是 BTreeSet<String> 所以我添加了一个 map(|x| to string() ) 来创建 i。然后它有点工作并且比以前更快。但是现在它几乎与 python 版本完全一样。 9.5 秒 rust 和 9.0 python
【解决方案2】:

查找列表ab 之间是否有共同元素:

如果你的元素是可比较的,你可以对两个列表进行排序,然后扫描列表,类似于 merge sort 迭代。除非你到达a[i]==b[k] 的点,否则你找到了一个交叉点并可以返回true

如果不可能对元素强加顺序,这个策略就不会奏效。

【讨论】:

  • 我根本不明白这是如何回答问题的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多