检查一个数组是不是是另一个数组的子集

     2023-02-27     210

关键词:

【中文标题】检查一个数组是不是是另一个数组的子集【英文标题】:Check whether an array is a subset of another检查一个数组是否是另一个数组的子集 【发布时间】:2010-09-24 21:09:30 【问题描述】:

知道如何检查该列表是否是另一个列表的子集吗?

具体来说,我有

List<double> t1 = new List<double>  1, 3, 5 ;
List<double> t2 = new List<double>  1, 5 ;

如何使用 LINQ 检查 t2 是否为 t1 的子集?

【问题讨论】:

如果列表已排序(如您的示例所示),这应该可以在 O(n+m) 时间内完成。 【参考方案1】:
bool isSubset = !t2.Except(t1).Any();

【讨论】:

我已经创建了扩展方法geekswithblogs.net/mnf/archive/2011/05/13/… @Bul Ikana 这段代码的工作很简单,如果没有为该作业提供 IEqualityComparer,扩展方法在内部调用被覆盖的对象类方法的 Equals 和 GetHashCode。 如果列表长度为n和m,这个算法的时间复杂度是多少? 如果将其归结为一个名为 ContainsAll 的 linq 方法会很好 我想知道交叉路口是否会更快 - t1.Intersect(t2).Count() == t2.Count()【参考方案2】:

如果使用集合,请使用 HashSet 而不是 List。然后你可以简单地使用IsSubsetOf()

HashSet<double> t1 = new HashSet<double>1,3,5;
HashSet<double> t2 = new HashSet<double>1,5;

bool isSubset = t2.IsSubsetOf(t1);

抱歉,它不使用 LINQ。 :-(

如果您需要使用列表,那么@Jared 的解决方案适用于需要删除任何存在的重复元素的警告。

【讨论】:

没错。你想要一个集合操作,使用为他们设计的类。 Cameron 的解决方案很有创意,但不如 HashSet 清晰/富有表现力。 嗯,我不同意,因为这个问题专门说“使用 LINQ”。 @JaredPar:那又怎样?向某人展示正确的方式不是比他们想走的路更好吗? 一个列表保持它的顺序,但一个集合没有。如果顺序很重要,这将给出不正确的结果。【参考方案3】:

这是一个比此处发布的其他解决方案更有效的解决方案,尤其是***解决方案:

bool isSubset = t2.All(elem => t1.Contains(elem));

如果您可以在 t2 中找到一个不在 t1 中的元素,那么您就知道 t2 不是 t1 的子集。与使用 .Except 或 .Intersect 的解决方案不同,这种方法的优点是它全部就地完成,无需分配额外的空间。此外,该解决方案能够在找到违反子集条件的单个元素时立即中断,而其他元素继续搜索。下面是解决方案的最佳长形式,在我的测试中它只比上述速记解决方案快一点。

bool isSubset = true;
foreach (var element in t2) 
    if (!t1.Contains(element)) 
        isSubset = false;
        break;
    

我对所有解决方案进行了一些基本的性能分析,结果非常惊人。这两个解决方案比 .Except() 和 .Intersect() 解决方案快大约 100 倍,并且不使用额外的内存。

【讨论】:

这正是!t2.Except(t1).Any() 正在做的事情。 Linq 来回工作。 Any() 询问IEnumerable 是否至少有一个元素。在这种情况下,t2.Except(t1) 只发出t2 的第一个元素,它不在t1 中。如果t2 的第一个元素不在t1 中,则运行速度最快,如果t2 的所有元素都在t1 中,则运行时间最长。 在使用某种基准测试时,我发现,当您使用t1=1,2,3,...9999t2=9999,9998,99997...9000 时,您会得到以下测量结果:!t2.Except(t1).Any(): 1ms -&gt; t2.All(e =&gt; t1.Contains(e)): 702ms。范围越大,情况就越糟。 这不是 Linq 的工作方式。 t2.Except (t1) 返回的是 IEnumerable 而不是 Collection。如果您完全迭代它,它只会发出所有可能的项目,例如通过ToArray ()ToList () 或使用foreach 而不会破坏内部。搜索 linq deferred execution 以了解有关该概念的更多信息。 我完全了解延迟执行在 Linq 中的工作原理。您可以随心所欲地推迟执行,但是当您想确定 t2 是否是 t1 的子集时,您需要遍历整个列表才能弄清楚。这个事实是无法回避的。 让我们以您的评论为例 t2=1,2,3,4,5,6,7,8 t1=2,4,6,8 t2.Except(t1) => t2 的第一个元素 = 1 => 1的差异> 到 t1 是 1 (检查 2,4,6,8)=> Except() 发出第一个元素 1 => Any() 得到一个元素 = > Any() 结果为真 => 不再检查 t2 中的元素。【参考方案4】:

如果你是单元测试,你也可以使用CollectionAssert.IsSubsetOf 方法:

CollectionAssert.IsSubsetOf(subset, superset);

在上述情况下,这意味着:

CollectionAssert.IsSubsetOf(t2, t1);

【讨论】:

【参考方案5】:

@Cameron 作为扩展方法的解决方案:

public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)

    return !a.Except(b).Any();

用法:

bool isSubset = t2.IsSubsetOf(t1);

(这与@Michael 博客上发布的类似,但不完全相同)

【讨论】:

【参考方案6】:

我花了一些时间使用 BenchmarkDotNet 对这个答案中的 3 个有效解决方案进行基准测试。

!t2.Except(t1).Any() 调用了 except().Any() t2.IsSubsetOf(t1) 称为HashSet t2.All(elem =&gt; t1.Contains(elem)) 调用所有(=>包含)

我改变了 3 个参数:

超集计数 子集长度 项目的可变性

所有超集的长度都是随机的,并且包含[0; Variability) 范围内的项目。子集的长度固定,包含[0; Variability) 范围内的项目。

赢家是 All(=>Contains) 方法 - 它有时比使用 HashSet 快 30 倍,比 except().Any() 快 50 倍。

代码可以在github找到

更新 正如@Gert Arnold 在 cmets 中提到的那样,我的基准测试中有一个错误。我在每次迭代中都调用了ToHashSet()。 因此,我还构建了一组预构建的哈希集,并添加了一个名为 prebuilt HashSet 的纯哈希集测试。 它不是绝对的赢家,有时它会失去All(=&gt;Contains) 算法。在我看来,重点在于超集的可变性(和重复)。当值的可变性较低时 - 哈希集获胜,因为它会将其从数据中删除。

决赛桌在这里:

|             Method | SupersetsInIteration | SubsetLength | Variability |          Mean |        Error |       StdDev |        Median |
|------------------- |--------------------- |------------- |------------ |--------------:|-------------:|-------------:|--------------:|
|     Except().Any() |                 1000 |           10 |         100 |   1,485.89 μs |     7.363 μs |     6.887 μs |   1,488.36 μs |
|        ToHashSet() |                 1000 |           10 |         100 |   1,015.59 μs |     5.099 μs |     4.770 μs |   1,015.43 μs |
| prebuilt HashSet   |                 1000 |           10 |         100 |      38.76 μs |     0.065 μs |     0.054 μs |      38.78 μs |
|    All(=>Contains) |                 1000 |           10 |         100 |     105.46 μs |     0.320 μs |     0.267 μs |     105.38 μs |
|     Except().Any() |                 1000 |           10 |       10000 |   1,912.17 μs |    38.180 μs |    87.725 μs |   1,890.72 μs |
|        ToHashSet() |                 1000 |           10 |       10000 |   1,038.70 μs |    20.028 μs |    40.459 μs |   1,019.35 μs |
| prebuilt HashSet   |                 1000 |           10 |       10000 |      28.22 μs |     0.165 μs |     0.155 μs |      28.24 μs |
|    All(=>Contains) |                 1000 |           10 |       10000 |      81.47 μs |     0.117 μs |     0.109 μs |      81.45 μs |
|     Except().Any() |                 1000 |           50 |         100 |   4,888.22 μs |    81.268 μs |    76.019 μs |   4,854.42 μs |
|        ToHashSet() |                 1000 |           50 |         100 |   4,323.23 μs |    21.424 μs |    18.992 μs |   4,315.16 μs |
| prebuilt HashSet   |                 1000 |           50 |         100 |     186.53 μs |     1.257 μs |     1.176 μs |     186.35 μs |
|    All(=>Contains) |                 1000 |           50 |         100 |   1,173.37 μs |     2.667 μs |     2.227 μs |   1,173.08 μs |
|     Except().Any() |                 1000 |           50 |       10000 |   7,148.22 μs |    20.545 μs |    19.218 μs |   7,138.22 μs |
|        ToHashSet() |                 1000 |           50 |       10000 |   4,576.69 μs |    20.955 μs |    17.499 μs |   4,574.34 μs |
| prebuilt HashSet   |                 1000 |           50 |       10000 |      33.87 μs |     0.160 μs |     0.142 μs |      33.85 μs |
|    All(=>Contains) |                 1000 |           50 |       10000 |     131.34 μs |     0.569 μs |     0.475 μs |     131.24 μs |
|     Except().Any() |                10000 |           10 |         100 |  14,798.42 μs |   120.423 μs |   112.643 μs |  14,775.43 μs |
|        ToHashSet() |                10000 |           10 |         100 |  10,263.52 μs |    64.082 μs |    59.942 μs |  10,265.58 μs |
| prebuilt HashSet   |                10000 |           10 |         100 |   1,241.19 μs |     4.248 μs |     3.973 μs |   1,241.75 μs |
|    All(=>Contains) |                10000 |           10 |         100 |   1,058.41 μs |     6.766 μs |     6.329 μs |   1,059.22 μs |
|     Except().Any() |                10000 |           10 |       10000 |  16,318.65 μs |    97.878 μs |    91.555 μs |  16,310.02 μs |
|        ToHashSet() |                10000 |           10 |       10000 |  10,393.23 μs |    68.236 μs |    63.828 μs |  10,386.27 μs |
| prebuilt HashSet   |                10000 |           10 |       10000 |   1,087.21 μs |     2.812 μs |     2.631 μs |   1,085.89 μs |
|    All(=>Contains) |                10000 |           10 |       10000 |     847.88 μs |     1.536 μs |     1.436 μs |     847.34 μs |
|     Except().Any() |                10000 |           50 |         100 |  48,257.76 μs |   232.573 μs |   181.578 μs |  48,236.31 μs |
|        ToHashSet() |                10000 |           50 |         100 |  43,938.46 μs |   994.200 μs | 2,687.877 μs |  42,877.97 μs |
| prebuilt HashSet   |                10000 |           50 |         100 |   4,634.98 μs |    16.757 μs |    15.675 μs |   4,643.17 μs |
|    All(=>Contains) |                10000 |           50 |         100 |  10,256.62 μs |    26.440 μs |    24.732 μs |  10,243.34 μs |
|     Except().Any() |                10000 |           50 |       10000 |  73,192.15 μs |   479.584 μs |   425.139 μs |  73,077.26 μs |
|        ToHashSet() |                10000 |           50 |       10000 |  45,880.72 μs |   141.497 μs |   125.433 μs |  45,860.50 μs |
| prebuilt HashSet   |                10000 |           50 |       10000 |   1,620.61 μs |     3.507 μs |     3.280 μs |   1,620.52 μs |
|    All(=>Contains) |                10000 |           50 |       10000 |   1,460.01 μs |     1.819 μs |     1.702 μs |   1,459.49 μs |
|     Except().Any() |               100000 |           10 |         100 | 149,047.91 μs | 1,696.388 μs | 1,586.803 μs | 149,063.20 μs |
|        ToHashSet() |               100000 |           10 |         100 | 100,657.74 μs |   150.890 μs |   117.805 μs | 100,654.39 μs |
| prebuilt HashSet   |               100000 |           10 |         100 |  12,753.33 μs |    17.257 μs |    15.298 μs |  12,749.85 μs |
|    All(=>Contains) |               100000 |           10 |         100 |  11,238.79 μs |    54.228 μs |    50.725 μs |  11,247.03 μs |
|     Except().Any() |               100000 |           10 |       10000 | 163,277.55 μs | 1,096.107 μs | 1,025.299 μs | 163,556.98 μs |
|        ToHashSet() |               100000 |           10 |       10000 |  99,927.78 μs |   403.811 μs |   337.201 μs |  99,812.12 μs |
| prebuilt HashSet   |               100000 |           10 |       10000 |  11,671.99 μs |     6.753 μs |     5.986 μs |  11,672.28 μs |
|    All(=>Contains) |               100000 |           10 |       10000 |   8,217.51 μs |    67.959 μs |    56.749 μs |   8,225.85 μs |
|     Except().Any() |               100000 |           50 |         100 | 493,925.76 μs | 2,169.048 μs | 1,922.805 μs | 493,386.70 μs |
|        ToHashSet() |               100000 |           50 |         100 | 432,214.15 μs | 1,261.673 μs | 1,180.169 μs | 431,624.50 μs |
| prebuilt HashSet   |               100000 |           50 |         100 |  49,593.29 μs |    75.300 μs |    66.751 μs |  49,598.45 μs |
|    All(=>Contains) |               100000 |           50 |         100 |  98,662.71 μs |   119.057 μs |   111.366 μs |  98,656.00 μs |
|     Except().Any() |               100000 |           50 |       10000 | 733,526.81 μs | 8,728.516 μs | 8,164.659 μs | 733,455.20 μs |
|        ToHashSet() |               100000 |           50 |       10000 | 460,166.27 μs | 7,227.011 μs | 6,760.150 μs | 457,359.70 μs |
| prebuilt HashSet   |               100000 |           50 |       10000 |  17,443.96 μs |    10.839 μs |     9.608 μs |  17,443.40 μs |
|    All(=>Contains) |               100000 |           50 |       10000 |  14,222.31 μs |    47.090 μs |    44.048 μs |  14,217.94 μs |

【讨论】:

比较不公平。您在测量代码中包含ToHashSet()。如果您创建散列集并仅比较IsSubsetOf,结果会大不相同。毫无疑问HashSet 会轻松获胜。 好点,谢谢!我将在全局设置中对准备好的哈希集重新运行测试。我已经将它包含在基准代码中,因为我们通常不会在常见的业务代码中使用这种特定的数据结构,但我会检查一下。【参考方案7】:

基于@Cameron 和@Neil 的答案,我编写了一个扩展方法,它使用与 Enumerable 类相同的术语。

/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)

    return !values.Except(source).Any();

【讨论】:

【参考方案8】:

假设我们有 2 个数组,array1array2,我们想检查 array2 中是否存在所有 array1 值:

array1.All(ar1 => array2.Any(ar2 => ar2.Equals(ar1)));

注意:ar2.Equals(ar1) 如果以其他方式描述相等,则可以替换。

【讨论】:

【参考方案9】:

试试这个

static bool IsSubSet<A>(A[] set, A[] toCheck) 
  return set.Length == (toCheck.Intersect(set)).Count();

这里的想法是 Intersect 只会返回两个数组中的值。此时如果结果集的长度与原始集相同,那么“set”中的所有元素也都在“check”中,因此“set”是“toCheck”的子集

注意:如果“set”有重复项,我的解决方案将不起作用。我不会改变它,因为我不想窃取别人的选票。

提示:我投票支持卡梅伦的答案。

【讨论】:

如果它们确实是集合,则此方法有效,但如果第二个“集合”包含重复元素则无效,因为它实际上是一个列表。您可能希望使用 HashSet 来确保它已设置语义。 当两个数组都有元素时不起作用,而这些元素不在另一个数组中。【参考方案10】:

这里我们检查子列表(即t2)中是否存在不包含在父列表(即t1)中的任何元素。如果不存在,则该列表是另一个列表的子集

例如:

bool isSubset = !(t2.Any(x => !t1.Contains(x)));

【讨论】:

not Any not 与普通的All 相同。

如何检查一个字典是不是是另一个更大字典的子集?

】如何检查一个字典是不是是另一个更大字典的子集?【英文标题】:Howtocheckifonedictionaryisasubsetofanotherlargerdictionary?如何检查一个字典是否是另一个更大字典的子集?【发布时间】:2012-03-0814:05:28【问题描述】:我正在尝试编写... 查看详情

在 Impala 中使用字符串或数组检查子集

】在Impala中使用字符串或数组检查子集【英文标题】:ChecksubsetusingeitherstringorarrayinImpala【发布时间】:2018-05-2308:27:24【问题描述】:我有一张这样的桌子col-----A,Bcol可以是带逗号的字符串或数组。我在存储方面具有灵活性。如何... 查看详情

如何确定一个列表是不是是另一个列表的子集?

】如何确定一个列表是不是是另一个列表的子集?【英文标题】:Howtodetermineifalistissubsetofanotherlist?如何确定一个列表是否是另一个列表的子集?【发布时间】:2009-08-2615:53:06【问题描述】:确定一个列表是否是另一个列表的子... 查看详情

检查数组是不是包含在 PostgreSQL 中的另一个数组中

】检查数组是不是包含在PostgreSQL中的另一个数组中【英文标题】:CheckingifarrayiscontainedinanotherarrayinPostgreSQL检查数组是否包含在PostgreSQL中的另一个数组中【发布时间】:2014-01-2207:10:51【问题描述】:有一个数组[10,20],我想知道... 查看详情

如何证明一个集合是另一个集合的子集

怎样证明一个集合是另一个集合的子集?怎样证明一个集合是另一个集合的子集,又怎样证明一个集合不是另一个集合的子集?参考技术A在一个集合中任取一个元素,都满足这个元素属于另一个集合,则这个集合是另一个集合的子集.... 查看详情

java示例代码_HQL(Hibernate)如何检查一个元素列表是否是另一个列表的子集

java示例代码_HQL(Hibernate)如何检查一个元素列表是否是另一个列表的子集 查看详情

元组是另一个元组的子集 - Apriori 算法

】元组是另一个元组的子集-Apriori算法【英文标题】:Tupleissubsetofanothertuple-Apriorialgortihm【发布时间】:2018-10-2511:11:55【问题描述】:我正在尝试实现先验算法。在最后一个步骤中,我有两个从产品列表生成的元组数组。>>>... 查看详情

如何检查一个值是不是在数组中并使用复选框进行检查

】如何检查一个值是不是在数组中并使用复选框进行检查【英文标题】:Howtocheckifavalueisinanarrayandcheckitwithcheckboxes如何检查一个值是否在数组中并使用复选框进行检查【发布时间】:2020-01-2614:28:59【问题描述】:我有一个带有worl... 查看详情

Numpy数组获取不是NaN的数组的子集/切片

...hisnotNaN【发布时间】:2013-06-1204:02:57【问题描述】:我有一个大小数组:(50,50)。在这个数组中有一个大小为(20,10)的切片。只有这个slice包含数据,其余的都设置为nan。如何从我的大数组中切出这个切片?【问题讨论】:【参考... 查看详情

如何检查一个数组是不是包含另一个数组的任何元素

】如何检查一个数组是不是包含另一个数组的任何元素【英文标题】:Howtocheckifanarraycontainsanyelementsofanotherarray如何检查一个数组是否包含另一个数组的任何元素【发布时间】:2022-01-0920:42:29【问题描述】:这里有一个数组["chair"... 查看详情

检查一个数组是不是包含另一个数组的所有元素

】检查一个数组是不是包含另一个数组的所有元素【英文标题】:Checkingifanarraycontainsallelementsofanotherarray检查一个数组是否包含另一个数组的所有元素【发布时间】:2012-10-1221:25:01【问题描述】:我正在设计一个电气工程应用程... 查看详情

检查一个数组是不是包含 JavaScript 中另一个数组的任何元素

】检查一个数组是不是包含JavaScript中另一个数组的任何元素【英文标题】:CheckifanarraycontainsanyelementofanotherarrayinJavaScript检查一个数组是否包含JavaScript中另一个数组的任何元素【发布时间】:2020-03-1000:00:03【问题描述】:我有一... 查看详情

检查一个数组是不是包含 JavaScript 中另一个数组的任何元素

】检查一个数组是不是包含JavaScript中另一个数组的任何元素【英文标题】:CheckifanarraycontainsanyelementofanotherarrayinJavaScript检查一个数组是否包含JavaScript中另一个数组的任何元素【发布时间】:2013-04-2502:51:41【问题描述】:我有一... 查看详情

如何检查包含另一个对象数组的对象数组是不是具有属性

】如何检查包含另一个对象数组的对象数组是不是具有属性【英文标题】:Howtocheckifarrayofobjectsthatcontainsanotherarrayofobjecthasproperty如何检查包含另一个对象数组的对象数组是否具有属性【发布时间】:2021-12-2617:25:19【问题描述】:... 查看详情

Hive:如何检查一个数组的值是不是存在于另一个数组中?

】Hive:如何检查一个数组的值是不是存在于另一个数组中?【英文标题】:Hive:Howtocheckifvaluesofonearrayarepresentinanother?Hive:如何检查一个数组的值是否存在于另一个数组中?【发布时间】:2017-02-0111:34:05【问题描述】:我有两个... 查看详情

使用 RSpec 检查某物是不是是另一个对象的实例

】使用RSpec检查某物是不是是另一个对象的实例【英文标题】:UsingRSpectocheckifsomethingisaninstanceofanotherobject使用RSpec检查某物是否是另一个对象的实例【发布时间】:2012-11-1222:58:40【问题描述】:我需要一种方法来使用RSpec检查一... 查看详情

检查一个列表是不是是另一个与重复项一起使用的列表的轮换

】检查一个列表是不是是另一个与重复项一起使用的列表的轮换【英文标题】:Checkifalistisarotationofanotherlistthatworkswithduplicates检查一个列表是否是另一个与重复项一起使用的列表的轮换【发布时间】:2015-09-0902:57:02【问题描述】... 查看详情

有没有办法检查一个数组的任何内容是不是在 Roblox 的另一个数组中

】有没有办法检查一个数组的任何内容是不是在Roblox的另一个数组中【英文标题】:IsthereawaytocheckifanycontentofaarrayisinanotherarrayinRoblox有没有办法检查一个数组的任何内容是否在Roblox的另一个数组中【发布时间】:2021-04-0317:13:00【... 查看详情