【问题标题】:How to compare two List<String> to each other? [duplicate]如何将两个 List<String> 相互比较? [复制]
【发布时间】:2012-03-25 01:06:01
【问题描述】:

假设有

List<string> a1 = new List<string>();

List<string> a2 = new List<string>();

有没有办法做到这一点?

if (a1 == a2) 
{

}

【问题讨论】:

  • 您到底希望它做什么?如果两个列表具有相同的值且顺序相同,则返回 true?

标签: c# .net


【解决方案1】:

您也可以使用Except(产生两个序列的集合差)来检查是否存在差异:

IEnumerable<string> inFirstOnly = a1.Except(a2);
IEnumerable<string> inSecondOnly = a2.Except(a1);
bool allInBoth = !inFirstOnly.Any() && !inSecondOnly.Any();

因此,如果顺序和重复的数量无关紧要(与接受的答案 SequenceEqual 相反),这是一种有效的方法。演示:Ideone

如果您想以不区分大小写的方式进行比较,只需添加StringComparer.OrdinalIgnoreCase

a1.Except(a2, StringComparer.OrdinalIgnoreCase)

【讨论】:

  • 使用 Except 的两个潜在问题:它只会返回 a1 中不存在于 a2 中的项目 - 所以如果 a2 包含额外的项目,这将返回假阴性。其次,它不考虑同一项目的重复,只考虑存在。仍然是一个强大的工具,只是需要小心使用。
  • @AndrewHanlon:我想起了这个答案和你的评论,所以我添加了一些额外的信息和一种双向检查的方法 - 8.5 年后:D
【解决方案2】:

如果要检查列表内的元素是否相等且顺序相同,可以使用SequenceEqual

if (a1.SequenceEqual(a2))

在线查看:ideone

【讨论】:

  • 别忘了你也可以实现自己的IEqualityComparer 并将其作为第二个参数提供(例如a IgnoreCase comparer for string)。
  • @MarkByers,当我在我的系统中尝试 SequenceEqual() 时,为什么它抛出像 List 这样的异常不包含“SequenceEqual”的定义并且没有扩展方法“SequenceEqual”接受类型的第一个参数......
  • @SaiKalyanAkshinthala:首先,这看起来更像是编译器错误而不是异常。确保您使用的是 .NET 3.5 或更高版本,并且您有一个 using System.Linq 指令。另请查看我发布的 ideone 链接以查看完整的示例。您应该能够将其复制并粘贴到您的 IDE 中并运行它。
  • 我知道这是一个令人难以置信的迟到的评论,但我觉得重要的是要注意,如果其中一个列表是 null,这将引发异常。
  • 我发现了一个不起作用的案例。不知何故,我列表中的公共项目是相同的并且具有相同的计数。但是 PRIVATE 项目不同:其中一个有一个额外的 null 项目。我不知道为什么(我专门用 .Where(item => item != null) 生成了列表。这种私人差异使得 SequenceEqual 返回 false。
【解决方案3】:
    private static bool CompareDictionaries(IDictionary<string, IEnumerable<string>> dict1, IDictionary<string, IEnumerable<string>> dict2)
    {
        if (dict1.Count != dict2.Count)
        {
            return false;
        }

        var keyDiff = dict1.Keys.Except(dict2.Keys);
        if (keyDiff.Any())
        {
            return false;
        }

        return (from key in dict1.Keys 
                let value1 = dict1[key] 
                let value2 = dict2[key] 
                select value1.Except(value2)).All(diffInValues => !diffInValues.Any());
    }

【讨论】:

    【解决方案4】:

    我发现SequenceEqual 并不是比较两个字符串列表的最有效方法(最初来自http://www.dotnetperls.com/sequenceequal)。

    我想自己测试一下,所以我创建了两种方法:

        /// <summary>
        /// Compares two string lists using LINQ's SequenceEqual.
        /// </summary>
        public bool CompareLists1(List<string> list1, List<string> list2)
        {
            return list1.SequenceEqual(list2);
        }
    
        /// <summary>
        /// Compares two string lists using a loop.
        /// </summary>
        public bool CompareLists2(List<string> list1, List<string> list2)
        {
            if (list1.Count != list2.Count)
                return false;
    
            for (int i = 0; i < list1.Count; i++)
            {
                if (list1[i] != list2[i])
                    return false;
            }
    
            return true;
        }
    

    第二种方法是我遇到的一段代码,想知道是否可以将其重构为“更易于阅读”。 (并且还想知道 LINQ 优化是否会更快。)

    事实证明,两个包含 32k 字符串的列表,超过 100 次执行:

    • 方法 1 平均耗时 6761.8 个滴答声
    • 方法 2 平均耗时 3268.4 个滴答声

    为了简洁、性能和代码可读性,我通常更喜欢 LINQ;但在这种情况下,我认为基于循环的方法是首选。

    编辑:

    我使用优化的代码重新编译,并运行了 1000 次迭代的测试。结果仍然有利于循环(更是如此):

    • 方法 1 平均耗时 4227.2 个滴答声
    • 方法 2 平均耗时 1831.9 个滴答声

    在 Core i7-920 上使用 Visual Studio 2010、C# .NET 4 客户端配置文件进行测试

    【讨论】:

    • 这不是一个公平的比较,原因有两个:1. Equals 没有被使用,2. 它只适用于列表,这对于这个问题来说是可以的。
    • 如果 list2 与 list1 有相同的项目,但又比 list1 多一个项目,这不会仍然返回 true 吗?您是否必须通过 list2 进行第二次循环并进行相同的比较?
    • @PeterTirrell 否,因为它首先比较 .Count 属性。
    • @JYelton 啊,是的,我的错。我意识到事后我使用的单元测试还有另一个缺陷。谢谢!
    【解决方案5】:

    您可以通过以下所有方式查看列表

    List<string> FilteredList = new List<string>();
    //Comparing the two lists and gettings common elements.
    FilteredList = a1.Intersect(a2, StringComparer.OrdinalIgnoreCase);
    

    【讨论】:

    • 我没有投反对票 - 但您的回答实际上并没有解决 OP 的问题。它会产生一个交叉点,因此您需要执行额外的步骤来检查该交叉点是否与 a1a2 匹配。
    • 另外,Intersect 会丢弃重复项,所以这只会检查 a1a2 中的不同元素。
    猜你喜欢
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 2014-12-03
    • 2015-11-15
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 2013-06-08
    相关资源
    最近更新 更多