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

时间:2011-03-02 02:35:50

标签: c#

假设我有两个集合如下:

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

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

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

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

5 个答案:

答案 0 :(得分:33)

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

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

答案 1 :(得分:19)

是的,如果您没有空间受限,可以采用更快的方式。 (见space/time tradeoff。)

算法:

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

或者,只需说:

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

修改1:

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

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


编辑2:

如果字符串非常大并且您关注空间效率,并且使用(非常)高概率的算法适合您,则尝试存储每个字符串的哈希。从技术上讲,保证不起作用,但它不起作用的可能性非常低。

答案 2 :(得分:5)

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

var list1 = new List<string> { "A1", "A1", "M1", "M2" };
var list2 = new List<string> { "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。只有当你将它用作比较或控制但之后不需要内容时才这样做。

答案 3 :(得分:3)

查看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);
}

答案 4 :(得分:0)

类似的

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));