Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
快速检查两个列表是否相同的方法c#_C#_Linq_Ienumerable - Fatal编程技术网

快速检查两个列表是否相同的方法c#

快速检查两个列表是否相同的方法c#,c#,linq,ienumerable,C#,Linq,Ienumerable,假设有以下两个强类型列表: 列表1:现有项目 身份证、姓名、猫 1,ABC,C2,BCD,D 3,NNN,F 清单2:新项目 ID、名称、类别 9,ABC,C 15,BCD,D 12,NNN,F 基本上,我想检查两个列表中的Name和Cat值是否相同。如果这两列上的两个列表相同,则返回true,否则返回false 我尝试了一些主要围绕以下内容的变化,但似乎总是返回true,即使newitems列表有一个新行,我希望返回false newitems.Any(x1 => existingit

假设有以下两个强类型列表:

列表1:现有项目

身份证、姓名、猫
1,ABC,C
2,BCD,D
3,NNN,F

清单2:新项目

ID、名称、类别
9,ABC,C
15,BCD,D
12,NNN,F

基本上,我想检查两个列表中的Name和Cat值是否相同。如果这两列上的两个列表相同,则返回true,否则返回false

我尝试了一些主要围绕以下内容的变化,但似乎总是返回true,即使newitems列表有一个新行,我希望返回false

newitems.Any(x1 => existingitems.All(x2 => (x1.Name== x2.Name) && (x1.Cat== x2.Cat)));


我相信这对你来说可能是最干净、最简单的解决方案

var list1Subset = list1.Select(i => new {i.Name, i.Cat});
var list2Subset = list2.Select(i => new {i.Name, i.Cat});

bool equal = list1Subset.SequenceEqual(list2Subset);

使用
哈希集和自定义比较器可以有效地执行此操作:

public class ItemComparer : IEqualityComparer<Item>
{
    public bool Equals(Item x, Item y)
    {
        return (x.Cat == y.Cat) && (x.Name == y.Name);
    }

    public int GetHashCode(Item obj)
    {
        return (obj.Cat.GetHashCode() * 17) + (obj.Name.GetHashCode() * 17);
    }
}

public bool AreEqual(IEnumerable<T> set1, IEnumerable<T> set2, 
    IEqualityComparer<T> equalityComparer)
{
    // Handle cheapest cases
    if (set1 == null && set2 == null)
    {
        return true;
    }
    else if (set1 == null && set2 != null
        || set1 != null && set2 == null)
    {
        return false;
    }
    else if (object.ReferenceEquals(set1, set2))
    {
        return true;
    }

    var hashSet1 = new HashSet<T>(set1, equalityComparer);
    var hashSet2 = new HashSet<T>(set2, equalityComparer);

    // More easy cases
    if (hashSet1.Count != hashSet2.Count)
    {
        return false;
    }

    if (set1.Any(i => !hashSet2.Contains(i))
        || set2.Any(i => !hashSet1.Contains(i)))
    {
        return false;
    }

    return true;
}
公共类ItemComparer:IEqualityComparer
{
公共布尔等于(项目x、项目y)
{
返回(x.Cat==y.Cat)&&(x.Name==y.Name);
}
公共int GetHashCode(项目obj)
{
返回值(obj.Cat.GetHashCode()*17)+(obj.Name.GetHashCode()*17);
}
}
公共布尔值相等(IEnumerable set1,IEnumerable set2,
IEqualityComparer(质量比较者与平等比较者)
{
//处理最便宜的案件
if(set1==null&&set2==null)
{
返回true;
}
else如果(set1==null&&set2!=null
||set1!=null&&set2==null)
{
返回false;
}
else if(object.ReferenceEquals(set1,set2))
{
返回true;
}
var hashSet1=新的HashSet(set1,equalityComparer);
var hashSet2=新的HashSet(set2,equalityComparer);
//更简单的案例

if(hashSet1.Count!=hashSet2.Count) { 返回false; } if(set1.Any(i=>!hashSet2.Contains(i)) ||set2.Any(i=>!hashSet1.Contains(i))) { 返回false; } 返回true; }
我们可以首先定义一种方法来确定两个序列是否相等:

public static bool SetEquals<T>(this IEnumerable<T> first
    , IEnumerable<T> second
    , IEqualityComparer<T> comparer = null)
{
    comparer = comparer ?? EqualityComparer<T>.Default;
    return new HashSet<T>(second).SetEquals(first);
}

为什么您希望返回false?在两个列表中,您的名称和Cat值是相同的。项目是否需要以相同的顺序排列?@Selman22我对返回false的评论是,如果新列表中有一行不在现有列表中。否则,返回true。无论如何,现在已经解决了。关于“两个列表中的内容相同”的要求确实有些不清楚。因此,各种不同的解决方案。有时最简单的解决方案是最好的。我甚至没有想过要走这条路,我会去做的。Thanks@Andy请注意,与其他所有解决方案不同,此解决方案要求每个列表中的项目顺序相同,这就是为什么它可以更简单的原因。如果项目顺序不同,则返回
false
。现在还不清楚这是否合适。实际上这很好,因为列表是按特定顺序排列的。@Servy是正确的。我假设(希望是正确的)顺序很重要,但没有指定。@Andy如果它们的顺序不一样怎么办?每个源序列迭代两次。@DanielGrankin不,我没有。我只迭代第二个序列一次,第一个序列要么部分迭代,要么最多完全迭代一次,这取决于短路是否发生。两个序列都没有迭代过两次。@Servy在我看来,每个Select、HashSet创建和调用上都有写操作。SetEquals(第一个)。@DanielGrankin
Select
将迭代源序列,创建一个中间序列,然后通过
HashSet
构造函数进行迭代
SetEquals
然后在访问内存集合中的数据时迭代另一个序列。所有这些都不涉及对源序列进行多次迭代。你的评论暗示你并不真正熟悉这里的潜在机制;在评论中不可能解释得更详细,我只能说你应该对LINQ和序列做更多的研究。@请注意,如果你使用其他中间序列,它不会减少写入的数量,如果序列包含大量重复项,但第一个序列可以包含比第二个序列更多的重复项,那么只有一个好处,而HashSet隐藏了这一点,HashSet将只包含一个重复项,并且您的方法将无法正常工作。我要么选择中间序列。我只能说,你应该对Collections进行更多的研究。hashSet1.Count!=hashSet2.数一数,如果一个IEnumerable中有相同名称和Cat的项,而另一个IEnumerable中只有一个,那该怎么办?@DanielGrankin很好地指出了这一点,但关于这些集是否有重复/重复的值,这并不是规范的一部分。我认为,如果不允许忽略重复项,我就不必忽略它,并制定更一般的解决方案。只是我的意见:)
public class ItemComparer : IEqualityComparer<Item>
{
    public bool Equals(Item x, Item y)
    {
        return (x.Cat == y.Cat) && (x.Name == y.Name);
    }

    public int GetHashCode(Item obj)
    {
        return (obj.Cat.GetHashCode() * 17) + (obj.Name.GetHashCode() * 17);
    }
}

public bool AreEqual(IEnumerable<T> set1, IEnumerable<T> set2, 
    IEqualityComparer<T> equalityComparer)
{
    // Handle cheapest cases
    if (set1 == null && set2 == null)
    {
        return true;
    }
    else if (set1 == null && set2 != null
        || set1 != null && set2 == null)
    {
        return false;
    }
    else if (object.ReferenceEquals(set1, set2))
    {
        return true;
    }

    var hashSet1 = new HashSet<T>(set1, equalityComparer);
    var hashSet2 = new HashSet<T>(set2, equalityComparer);

    // More easy cases
    if (hashSet1.Count != hashSet2.Count)
    {
        return false;
    }

    if (set1.Any(i => !hashSet2.Contains(i))
        || set2.Any(i => !hashSet1.Contains(i)))
    {
        return false;
    }

    return true;
}
public static bool SetEquals<T>(this IEnumerable<T> first
    , IEnumerable<T> second
    , IEqualityComparer<T> comparer = null)
{
    comparer = comparer ?? EqualityComparer<T>.Default;
    return new HashSet<T>(second).SetEquals(first);
}
var areEqual = list1.Select(item => new{item.Name, item.Cat})
    .SetEquals(list2.Select(item => new{item.Name, item.Cat}));