检查一个值集合是否包含另一个值

假设我有两个集合如下:

Collection1:“A1”“A1”“M1”“M2”

Collection2:“M2”“M3”“M1”“A1”“A1”“A2”

所有值都是字符串值。 我想知道Collection1中的所有元素是否包含在Collection2中,但我不保证顺序,并且一个集合可能有多个具有相同值的条目。 在这种情况下,Collection2确实包含Collection1,因为Collection2有两个A1,M1和M2。 这是显而易见的方式:在找到匹配项时对两个集合进行排序并弹出值,但我想知道是否有更快更有效的方法来执行此操作。 再次使用初始集合,我无法保证订单或给定值出现的次数

编辑:将集合更改为集合只是为了清除这些不是集合,因为它们可以包含重复值

是的,只要您没有空间受限,就有更快的方法。 (见空间/时间权衡 。)

算法:

只需将Set2中的所有元素插入一个哈希表(在C#3.5中,这是一个HashSet ),然后遍历Set1的所有元素并检查它们是否在哈希表中。 该方法更快(Θ(m + n)时间复杂度),但使用O(n)空间。

或者,只需说:

bool isSuperset = new HashSet(set2).IsSupersetOf(set1); 

编辑1:

对于那些担心重复的可能性(因此用词不当“设置”)的人来说,这个想法可以很容易地扩展:

只需创建一个新的Dictionary表示超级列表中每个单词的计数(每次看到现有单词的实例时,将其添加到计数中,如果不是,则添加计数为1的单词)在字典中),然后通过子列表并每次递减计数。 如果字典中存在每个单词, 并且当您尝试递减它时计数从不为零,那么该子集实际上是一个子列表; 否则,你有一个单词的实例太多(或根本不存在),所以它不是一个真正的子列表。


编辑2:

如果字符串非常大并且您关注空间效率,并且一个适用于(非常)高概率的算法适合您,那么请尝试存储每个字符串的散列 。 从技术上讲,它不能保证工作,但它不工作的可能性非常低。

我所知道的最简洁的方式:

 //determine if Set2 contains all of the elements in Set1 bool containsAll = Set1.All(s => Set2.Contains(s)); 

我在HashSet,Intersect和其他Set理论答案中看到的问题是你确实包含重复项,“A set是一个不包含重复元素的集合”。 这是处理重复案例的一种方法。

 var list1 = new List { "A1", "A1", "M1", "M2" }; var list2 = new List { "M2", "M3", "M1", "A1", "A1", "A2" }; // Remove returns true if it was able to remove it, and it won't be there to be matched again if there's a duplicate in list1 bool areAllPresent = list1.All(i => list2.Remove(i)); 

编辑 :我从Set1和Set2重命名为list1和list2以安抚Mehrdad。

编辑2 :评论意味着它,但我想明确声明这确实改变了list2。 如果您将其用作比较或控件但之后不需要内容,则只能这样做。

看看linq。 ..

 string[] set1 = {"A1", "A1", "M1", "M2" }; string[] set2 = { "M2", "M3", "M1", "A1", "A1", "A2" }; var matching = set1.Intersect(set2); foreach (string x in matching) { Console.WriteLine(x); } 

类似的

 string[] set1 = new string[] { "a1","a2","a3","a4","a5","aa","ab" }; string[] set2 = new string[] {"m1","m2","a4","a6","a1" }; var a = set1.Select(set => set2.Contains(set));