C# Distinct不使用LINQ to对象

C# Distinct不使用LINQ to对象,c#,.net,linq,iequatable,iequalitycomparer,C#,.net,Linq,Iequatable,Iequalitycomparer,Distinct()方法检查引用类型的引用相等性。这意味着它正在寻找字面上相同的复制对象,而不是包含相同值的不同对象 有一个接受,因此您可以指定不同的逻辑来确定给定对象是否等于另一个对象 如果希望作者的行为与普通对象一样正常(即仅引用相等),但为了按名称值检查相等性,请使用IEqualityComparer。如果总是希望基于名称值比较作者对象,则覆盖GetHashCode和Equals,或实现IEquatable IEqualityComparer界面上的两个成员是Equals和GetHashC

Distinct()
方法检查引用类型的引用相等性。这意味着它正在寻找字面上相同的复制对象,而不是包含相同值的不同对象

有一个接受,因此您可以指定不同的逻辑来确定给定对象是否等于另一个对象

如果希望作者的行为与普通对象一样正常(即仅引用相等),但为了按名称值检查相等性,请使用IEqualityComparer。如果总是希望基于名称值比较作者对象,则覆盖GetHashCode和Equals,或实现IEquatable

IEqualityComparer
界面上的两个成员是
Equals
GetHashCode
。确定两个
Author
对象是否相等的逻辑似乎是如果名字和姓氏字符串相同

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }
公共类AuthorEquals:IEqualityComparer
{
公共布尔等于(作者左、作者右)
{
如果((对象)左==null&&(对象)右==null)
{
返回true;
}
if((对象)left==null | |(对象)right==null)
{
返回false;
}
返回left.FirstName==right.FirstName&&left.LastName==right.LastName;
}
public int GetHashCode(作者)
{
return(author.FirstName+author.LastName).GetHashCode();
}
}

LINQ Distinct在定制对象方面并不是那么聪明

它所做的只是查看列表,看看它有两个不同的对象(不在乎它们的成员字段值是否相同)

一种解决方法是实现IEquatable接口,如图所示

如果您像这样修改Author类,它应该可以工作

public class AuthorEquals : IEqualityComparer<Author>
{
    public bool Equals(Author left, Author right)
    {
        if((object)left == null && (object)right == null)
        {
            return true;
        }
        if((object)left == null || (object)right == null)
        {
            return false;
        }
        return left.FirstName == right.FirstName && left.LastName == right.LastName;
    }

    public int GetHashCode(Author author)
    {
        return (author.FirstName + author.LastName).GetHashCode();
    }
}
public class Author:IEquatable

您已经覆盖了Equals(),但请确保您也覆盖了GetHashCode()

Distinct()
对可枚举对象执行默认的相等比较。如果未重写和,则它使用
对象
上的默认实现来比较引用

简单的解决方案是为参与比较对象图的所有类(即Book和Author)添加一个正确的实现


当您无法访问需要比较的类的内部时,或者如果您正在使用不同的比较方法时,该接口是一种方便的方式,允许您在一个单独的类中实现和。

另一种不实现
IEquatable
的解决方案,
Equals
GetHashCode
使用LINQs
GroupBy
方法,并从iGroup中选择第一项

public class Author : IEquatable<Author>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public bool Equals(Author other)
    {
        if (FirstName == other.FirstName && LastName == other.LastName)
            return true;

        return false;
    }

    public override int GetHashCode()
    {
        int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
        int hashLastName = LastName == null ? 0 : LastName.GetHashCode();

        return hashFirstName ^ hashLastName;
    }
}

以上答案是错误的!!! MSDN上声明的Distinct返回默认赤道,默认属性检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer否则,它返回一个EqualityComparer,使用T提供的Object.Equals和Object.GetHashCode的重写

这意味着只要你超越了平等,你就没事

您的代码无法运行的原因是您选中了firstname==lastname


请参见和

还有一种方法可以从用户定义的数据类型列表中获取不同的值:

var temp = books.SelectMany(book => book.Authors)
                .GroupBy (y => y.FirstName + y.LastName )
                .Select (y => y.First ());

foreach (var author in temp){
  Console.WriteLine(author.FirstName + " " + author.LastName);
}

当然,它将给出一组不同的数据

您可以使用扩展方法对列表进行扩展,该方法基于计算出的散列检查唯一性。 您还可以更改扩展方法以支持IEnumerable

示例:

YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();
public class Employee{
public string Name{get;set;}
public int Age{get;set;}
}

List<Employee> employees = new List<Employee>();
employees.Add(new Employee{Name="XYZ", Age=30});
employees.Add(new Employee{Name="XYZ", Age=30});

employees = employees.Unique(); //Gives list which contains unique objects. 
公共类员工{
公共字符串名称{get;set;}
公共整数{get;set;}
}
列出员工=新列表();
添加(新员工{Name=“XYZ”,年龄=30});
添加(新员工{Name=“XYZ”,年龄=30});
employees=employees.Unique()//提供包含唯一对象的列表。
扩展方法:

YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();
public class Employee{
public string Name{get;set;}
public int Age{get;set;}
}

List<Employee> employees = new List<Employee>();
employees.Add(new Employee{Name="XYZ", Age=30});
employees.Add(new Employee{Name="XYZ", Age=30});

employees = employees.Unique(); //Gives list which contains unique objects. 
公共静态类LinqExtension
{
公共静态列表唯一(此列表输入)
{
HashSet uniqueHashes=新HashSet();
列表唯一项=新列表();
input.ForEach(x=>
{
字符串hashCode=ComputeHash(x);
if(uniqueHashes.Contains(hashCode))
{
返回;
}
uniqueHashes.Add(hashCode);
唯一项目。添加(x);
});
归还独一无二的物品;
}
私有静态字符串ComputeHash(T实体)
{
System.Security.Cryptography.SHA1CryptoServiceProvider sh=新的System.Security.Cryptography.SHA1CryptoServiceProvider();
字符串输入=JsonConvert.SerializeObject(实体);
byte[]originalBytes=ascienceoding.Default.GetBytes(输入);
byte[]encodedBytes=sh.ComputeHash(原始字节);
返回BitConverter.ToString(encodedBytes).Replace(“-”,”);
}

您可以通过以下几种方式实现:

1。您可能需要实现如图所示或您可以看到的IEquatable接口

2.如果您的对象没有唯一键,您可以使用GroupBy方法获得不同的对象列表,您必须对对象的所有属性进行分组,然后选择第一个对象

例如,如下所示,为我工作:

    public static class LinqExtension
        {
            public static List<T> Unique<T>(this List<T> input)
            {
                HashSet<string> uniqueHashes = new HashSet<string>();
                List<T> uniqueItems = new List<T>();

                input.ForEach(x =>
                {
                    string hashCode = ComputeHash(x);

                    if (uniqueHashes.Contains(hashCode))
                    {
                        return;
                    }

                    uniqueHashes.Add(hashCode);
                    uniqueItems.Add(x);
                });

                return uniqueItems;
            }

            private static string ComputeHash<T>(T entity)
            {
                System.Security.Cryptography.SHA1CryptoServiceProvider sh = new System.Security.Cryptography.SHA1CryptoServiceProvider();
                string input = JsonConvert.SerializeObject(entity);

                byte[] originalBytes = ASCIIEncoding.Default.GetBytes(input);
                byte[] encodedBytes = sh.ComputeHash(originalBytes);

                return BitConverter.ToString(encodedBytes).Replace("-", "");
            }
MyObject类如下所示:

var distinctList= list.GroupBy(x => new {
                            Name= x.Name,
                            Phone= x.Phone,
                            Email= x.Email,
                            Country= x.Country
                        }, y=> y)
                       .Select(x => x.First())
                       .ToList()
3.如果对象的具有唯一键,则只能在“分组方式”中使用该键

例如,我的对象的唯一键是Id

public class MyClass{
       public string Name{get;set;}
       public string Phone{get;set;}
       public string Email{get;set;}
       public string Country{get;set;}
}

IEquatable很好,但不完整;您应该始终同时实现Object.Equals()和Object.GetHashCode();IEquatable.Equals不重写