检查 Vec 是否包含来自另一个 Vec 的所有元素

Check if Vec contains all elements from another Vec

提问人:Some Name 提问时间:10/6/2020 最后编辑:mcartonSome Name 更新时间:10/16/2023 访问量:10977

问:

有一个方法包含可用于检查特定元素是否存在于 .如何检查一个中的所有元素是否都包含在另一个元素中?有没有比手动迭代和显式检查所有元素更简洁的了?VecVecVec

矢量 集合 Rust

评论

2赞 mcarton 10/6/2020
other_vector.iter().all(|e| vector.contains(e)) 似乎还不错。
5赞 Masklinn 10/6/2020
另一种替代方法是在 HashSetBTreeSet 中加载并使用 is_subset/is_superset。这将具有更高的常数开销,但它应该是线性的而不是二次的,如果集合非常大,这可能是一个好主意。
0赞 Some Name 10/6/2020
@mcarton实际上,但我使用过的几乎所有语言都有一些开箱即用的东西。所以我问,以防万一我错过了什么,Rust 中有一些方法可以做到这一点。
3赞 Sven Marnach 10/6/2020
真?我不知道有一种语言支持开箱即用的类向量数据结构的子集检查。对于集合数据结构,当然,但对于向量则不然。
0赞 Some Name 10/6/2020
@SvenMarnach 至少这个

答:

-4赞 Iulian Radu 10/6/2020 #1

您还可以对向量进行排序,然后测试它们的相等性:

fn main() {
    let mut v1 = vec![2, 3, 1];
    let mut v2 = vec![3, 1, 2];
    
    v1.sort();
    v2.sort();

    assert_eq!(v1, v2);
}

评论

6赞 Masklinn 10/6/2020
请注意,他们问的是子集,而不仅仅是相等,例如 可能只是,但不是.v1132
30赞 Peter Hall 10/6/2020 #2

您有两个主要选择:

  • 天真地检查一个向量中的每个元素,看看它是否在另一个向量中。这具有时间复杂度 O(n^2),但它也非常简单且开销低:

    assert!(b.iter().all(|item| a.contains(item)));
    
  • 创建一个包含其中一个向量的所有元素的集合,然后检查另一个向量的元素是否包含在其中。这具有 O(n) 时间复杂度,但开销更高,包括额外的堆分配:

    let a_set: HashSet<_> = a.iter().copied().collect();
    assert!(b.iter().all(|item| a_set.contains(item)));
    

哪一个“更好”将取决于您的要求。如果你只关心速度,更好的选择仍然取决于向量中的元素数量,所以你应该用真实的数据来测试两者。您还可以使用 进行测试,它具有与 不同的性能特征。BTreeSetHashSet


以下是一些粗略的基准(来源),说明实现如何随输入大小而变化。在所有测试中,大小是 的一半,并且包含 元素的随机子集:baa

尺寸a Vec::contains HashSet::contains BtreeSet::contains
10 14 386 327
100 1,754 3,187 5,371
1000 112,306 31,233 88,340
10000 2,821,867 254,801 728,268
100000 29,207,999 2,645,703 6,611,666

以纳秒为单位的时间。

当元素数量较少时,朴素解速度最快。当大小大于约 200 时,分配 or 的开销会因比较次数的影响而黯然失色。 大多比 慢很多,但在元素数量非常少时略快。O(n^2)HashSetBTreeSetBTreeSetHashSet

1赞 x1hgg1x 7/2/2021 #3

如果你有排序的向量,你可以在线性时间内进行搜索:

    let mut vec = vec![0, 2, 4, 3, 6, 3, 5, 1, 0];
    let mut v = vec![1, 4, 3, 3, 1];

    vec.sort_unstable();
    v.sort_unstable();

    // Remove duplicates elements in v
    v.dedup();

    let mut vec_iter = vec.iter();
    assert!(v.iter().all(|&x| vec_iter.any(|&item| item == x)));

参考:C++ 具有 std::include,它正是这样做的。

评论

0赞 Peter Hall 7/30/2021
如果有重复的元素,这将给出不正确的结果 - 或者至少是不同的结果。如果要求另一个 vec 包含相同数量的每个项目,则这是正确的。v
0赞 x1hgg1x 7/31/2021
我已经编辑了我的答案以处理 中重复元素的情况。v
0赞 Dudeguy 10/16/2023 #4

在这里补充其他答案:根据你的设置方式,你可以通过比较它们的长度来节省一些比较。只有当 vec 的长度大于或等于 's 时,vec 才能包含(并且没有重复项。Vecabbb

assert!(a.len() >= b.len());