-2

我有 2 个字符串列表。有没有一种简单的方法来查找一个列表是否包含第二个列表的所有字符串?

(简单地说,我的意思是我没有明确地将一个列表中的每个字符串与所有字符串进行比较

4

4 回答 4

5

使用Enumerable.Except查找列表之间的差异。如果结果中没有项目,则 list2 中的所有项目都在 list1 中:

bool containsAll = !list2.Except(list1).Any();

内部Except用于Set<T>获取唯一项目list1并仅返回list2不在集合中的项目。如果没有什么可以返回,那么集合中的所有项目。

于 2013-08-20T13:10:06.253 回答
3

对于较大的列表,请使用 a HashSet<T>(这会导致线性大 O,而不是仅使用两个列表时的 O(n^2)):

var hash = new HashSet<string>(list2);
bool containsAll = list1.All(hash.Contains);
于 2013-08-20T13:11:00.803 回答
3

尝试这个:

firstList.All(x=>secondList.Contains(x));

较短的版本(方法组):

firstList.All(secondList.Contains)

您需要使用 for Linq 编写:

using System.Linq;

它检查第一个列表中的所有项目是否都在第二个列表中。Contains检查给定项目是否在列表中。All如果集合的所有项目都匹配谓词,则返回 true。给定谓词是:如果项目在第二个列表中,那么整个表达式检查是否所有项目都在第二个列表中 <- 证明工作:)

于 2013-08-20T13:09:07.753 回答
0

使用 LINQ

bool isSublistOf = list1.All(list2.Contains);

如果 lambda 中的每个元素都满足 lambda 中的条件,则 All 方法返回 true IEnumerable。All 被传递给 List2 的 Contains 方法,Func<bool,string>如果找到该元素则返回 true List2。最终效果是,如果在 List2 中找到 List1 中的所有元素,则该语句返回 true。

性能说明
由于 All 运算符的性质,最坏的情况是 O(n^2),但会在第一时间退出(任何不匹配)。使用完全随机的 8 字节字符串,我使用基本的性能工具尝试了每种情况。

    static void Main(string[] args)
    {
        long count = 5000000;
        //Get 5,000,000 random strings (the superset)
        var strings = CreateRandomStrings(count);

        //Get 1000 random strings (the subset)
        var substrings = CreateRandomStrings(1000);

        //Perform the hashing technique
        var start = DateTime.Now;
        var hash = new HashSet<string>(strings);
        var mid = DateTime.Now;
        var any = substrings.All(hash.Contains);
        var end = DateTime.Now;
        Console.WriteLine("Hashing took " + end.Subtract(start).TotalMilliseconds + " " + mid.Subtract(start).Milliseconds + " of which was setting up the hash");

        //Do the scanning all technique
        start = DateTime.Now;
        any = substrings.All(strings.Contains);
        end = DateTime.Now;
        Console.WriteLine("Scanning took " + end.Subtract(start).TotalMilliseconds);

        //Do the Excepting technique
        start = DateTime.Now;
        any = substrings.Except(strings).Any();
        end = DateTime.Now;
        Console.WriteLine("Excepting took " + end.Subtract(start).TotalMilliseconds);
        Console.ReadKey();

    }

    private static string[] CreateRandomStrings(long count)
    {
        var rng = new Random(DateTime.Now.Millisecond);
        string[] strings = new string[count];
        byte[] bytes = new byte[8];

        for (long i = 0; i < count; i++) {
            rng.NextBytes(bytes);
            strings[i] = Convert.ToBase64String(bytes);
        }
        return strings;
    }

结果相当一致地按以下顺序排列它们:

  1. 扫描 - ~38ms ( list1.All(list2.Contains))
  2. 散列 - 约 750 毫秒(其中 749 用于设置散列集)
  3. 例外 - 1200 毫秒

例外方法需要更长的时间,因为它需要预先完成所有工作。与其他方法不同,它不会在不匹配时退出,而是继续处理所有元素。散列要快得多,但在设置散列方面也做了重要的工作。如果字符串不那么随机并且交叉点更确定,这将是最快的方法。

免责声明
此级别的所有性能调整几乎都无关紧要。这只是一个心理锻炼而已

于 2013-08-20T13:09:18.747 回答