如何使用LINQ从集合的开头查找子集?

时间:2010-12-07 20:14:50

标签: c# linq

给定一系列对象(为简单起见,我将在本例中使用字符串)我想知道序列是否是另一个序列的子集,其中顺序很重要(我知道子集不是正确的单词,所以希望有人能告诉我正确的用语!)

基本上说我有一个序列

AABBCDEFG

我希望匹配其他字符串列表,使得它们在序列中的位置很重要(两个字符串中的第一个位置应该具有相同的对象,然后它将检查以下字符串等)。所以AAB将是AABBC的一个子集,但不是BCD。

使用for循环编写显然是一个非常简单的算法,例如:

        bool List1ContainedInList2(List<String> list1, List<String> list2)
        {
            // list1 should be the same size or smaller than list2
            if (list1.Count > list2.Count)
                return false;

            // in order all objects should be equal
            for (int i = 0; i < list1.Count; i++)
            {
                if (list1[i]!= list2[i])
                    return false;
            }

            // all reqs met
            return true;
        }

但是我一直在发现LINQ可以做多少酷炫有趣的事情,我想知道是否有一种简单的方法可以使用LINQ来实现这一目标?你会怎么做?谢谢!

2 个答案:

答案 0 :(得分:4)

最简单的方法是将较大的列表“修剪”为正确长度的序列,然后使用SequenceEqual运算符:

return list1.Count <= list2.Count && list2.Take(list1.Count)
                                          .SequenceEqual(list1);

或者,我们可以专注于索引(最接近您发布的代码):

return list1.Count <= list2.Count && Enumerable.Range(0, list1.Count)
                                               .All(i => list1[i] == list2[i]);

在.NET 4.0上,我们可以Zip序列向上(虽然Zip具有在达到任一序列结束后停止流式处理的良好属性,但我们仍然需要Count等式检查):

return list1.Count <= list2.Count && list1.Zip(list2, (s1, s2) => s1 == s2)
                                          .All(b => b);

或:

// This is an interesting one...
return list1.Zip(list2, (s1, s2) => s1 == s2)
            .Count(b => b) == list1.Count

我提到的所有选项以外的最后一个快速拒绝,即他们将停止枚举并在找到第一个不匹配时返回false

答案 1 :(得分:0)

您也可以尝试:

return list1.Take(list2.Count).SequenceEqual(list2);