假设我有两个集合如下:
Collection1: “A1” “A1” “M1” “M2”
Collection2: “M2” “M3” “M1” “A1” “A1” “A2”
所有值都是字符串值。我想知道Collection1中的所有元素是否都包含在Collection2中,但我不保证顺序,并且一个集合可能有多个具有相同值的条目。在这种情况下,Collection2包含Collection1,因为Collection2有两个A1,M1和M2。这是显而易见的方式:排序集合并在找到匹配时弹出值,但我想知道是否有更快更有效的方法来执行此操作。再次使用初始集合,我无法保证订单或给定值出现的次数
编辑:将设置更改为集合只是为了清除这些不是设置,因为它们可以包含重复值
答案 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));