亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#中Linq的去重方式Distinct詳解

 更新時間:2022年07月07日 10:38:50   作者:社會主義接班人  
本文詳細講解了C#中Linq的去重方式Distinct,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

前天在做批量數(shù)據(jù)導(dǎo)入新增時,要對數(shù)據(jù)進行有效性判斷,其中還要去除重復(fù),如果沒出現(xiàn)linq的話可能會新聲明一個臨時對象集合,然后遍歷原始數(shù)據(jù)判斷把符合條件的數(shù)據(jù)添加到臨時集合中,這在有了linq之后顯得比較麻煩。

一、首先創(chuàng)建一個控制臺應(yīng)用程序,添加一個Person對象

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compare
{
    public class Person
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

二、創(chuàng)建測試數(shù)據(jù)

創(chuàng)建了一個Name="ZhangSan"的Person對象,放入personList兩次,然后personList又創(chuàng)建了幾個Person對象,這幾個Person對象中也有Name、Age都重復(fù)的。例如:"XiaoMing",26.

            Person person = new Person("ZhangSan",26);
            List<Person> personList = new List<Person>() {
                person,
                new Person("XiaoMing",25),
                new Person("CuiYanWei",25),
                new Person("XiaoMing",26),
                 new Person("XiaoMing",25),
                new Person("LaoWang",26),
                new Person("XiaoMing",26),
                person
            };

三、測試

下面的代碼中用了兩種方式來選擇不重復(fù)的數(shù)據(jù)。

            List<Person> defaultDistinctPersons = personList.Distinct().ToList<Person>();
            foreach (Person p in defaultDistinctPersons)
            {
                Console.WriteLine("Name:{0}    Age:{1}",p.Name,p.Age);
            }
            Console.WriteLine("-----------------------------------------------------");
            List<Person> comparePersons = personList.Distinct(new PersonCompare()).ToList<Person>();
            foreach (Person p in comparePersons)
            {
                Console.WriteLine("Name:{0}    Age:{1}", p.Name, p.Age);
            }
            Console.ReadLine();

在華麗分割線上面是使用默認的distinct,下面是通過集成IEqualityComparer接口。下面是實現(xiàn)接口的代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compare
{
    public class PersonCompare:IEqualityComparer<Person>
    {
        public bool Equals(Person x, Person y)
        {
            if (x == null || y == null)
                return false;
            return x.Name.Equals(y.Name) && x.Age == y.Age;
        }
        public int GetHashCode(Person obj)
        {
            return obj.GetHashCode();
        }
    }
}

在上面的代碼中,繼承IEqualityComparer接口,主要是實現(xiàn)了兩個方法:bool Equals(T x, T y);int GetHashCode(T obj);可能即使實現(xiàn)了接口也不了解里面是怎么個原理,我們先看下運行結(jié)果。

從上面的運行結(jié)果可以看到,兩個運行結(jié)果是一樣的,還是有重復(fù)的數(shù)據(jù):例如XiaoMing,26.兩個都沒去除重復(fù),只有ZhangSan那兩個去除重復(fù)了。是不是有實現(xiàn)接口多此一舉的感覺。那為什么還要有這個接口還要實現(xiàn)它呢?其實要說下GetHashCode和Equals。

在說GetHashCode和Equals之前先了解下distinct(),這個方法Distinct 默認比較的是對象的引用,所以使用默認的distinct()方法是ZhangSan對象是過濾除去的,而XiaoMing,26是兩個不同的對象,沒有除去。

然后說下GetHashCode和Equals兩個方法.

1.哈希碼哈希代碼是一個用于在相等測試過程中標識對象的數(shù)值。它還可以作為一個集合中的對象的索引。如果兩個對象的 Equals 比較結(jié)果相等,則每個對象的 GetHashCode 方法都必須返回同一個值。 如果兩個對象的比較結(jié)果不相等,這兩個對象的 GetHashCode 方法不一定返回不同的值.
簡而言之,如果你發(fā)現(xiàn)兩個對象 GetHashCode() 的返回值相等,那么這兩個對象就很可能是同一個對象;但如果返回值不相等,這兩個對象一定不是同一個對象.

當(dāng)GetHashCode可以直接分辨出不相等時,Equals就沒必要調(diào)用了,而當(dāng)GetHashCode返回相同結(jié)果時,Equals方法會被調(diào)用從而確保判斷對象是否真的相等。所以,還是那句話:GetHashCode沒必要一定把對象分辨得很清楚(況且它也不可能,一個int不可能代表所有的可能出現(xiàn)的值),有Equals在后面做保障。GetHashCode僅需要對對象進行快速判斷。

上面的幾句算是總結(jié)性的說明了兩個方法的是怎么個路子,這也能解釋出ZhangSan的重復(fù)去除,而其他的幾個對象沒有去重復(fù)的原因,ZhangSan那是一個對象,其他的雖然Name、Age相等,但不是同一個對象。

我們可以稍微改動下代碼來驗證上面的語句.在實現(xiàn)IEqualityComparer的接口類中打印出一些信息就能看明白

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compare
{
    public class PersonCompare:IEqualityComparer<Person>
    {
        public bool Equals(Person x, Person y)
        {
            if (x == null || y == null)
                return false;
            Console.WriteLine("XName:{0} XAge:{1} XHashCode:{2}  YName:{3} YAge:{4} YHashCode:{5}", x.Name, x.Age, x.GetHashCode(),y.Name,y.Age,y.GetHashCode());
            return x.Name.Equals(y.Name) && x.Age == y.Age;
        }
        public int GetHashCode(Person obj)
        {
            Console.WriteLine("GetHashCode Name:{0} Age:{1} HashCode:{2}",obj.Name,obj.Age,obj.GetHashCode());
            return obj.GetHashCode();
        }
    }
}

在GetHashCode中打印了對象的Name、Age和HashCode??梢钥吹紿ashCode只有ZhangSan的是相同的,在Equals方法中只打印出了ZhangSan的,還是因為上面的先判斷HashCode,相等了再使用Equals判斷。

我們再改動下實現(xiàn)IEqualityComparer的接口類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compare
{
    public class PersonCompare:IEqualityComparer<Person>
    {
        public bool Equals(Person x, Person y)
        {
            if (x == null || y == null)
                return false;
            Console.WriteLine("XName:{0} XAge:{1} XHashCode:{2}  YName:{3} YAge:{4} YHashCode:{5}", x.Name, x.Age, x.GetHashCode(), y.Name, y.Age, y.GetHashCode());
            return x.Name.Equals(y.Name) && x.Age == y.Age;
        }
        public int GetHashCode(Person obj)
        {
            //Console.WriteLine("GetHashCode Name:{0} Age:{1} HashCode:{2}",obj.Name,obj.Age,obj.GetHashCode());
            //return obj.GetHashCode();
            string s = string.Format("{0}_{1}",obj.Name,obj.Age);
            Console.WriteLine("Name:{0} Age:{1} HashCode:{2}",obj.Name,obj.Age, s.GetHashCode());
            return s.GetHashCode();
        }
    }
}

根據(jù)上面的的代碼和測試結(jié)果我們可以看到,GetHashCode執(zhí)行了7次(7個對象),Equals執(zhí)行了3次,因為ZhangSan,26和XiaoMing,25兩個的哈希碼是一樣的就沒有繼續(xù)往下執(zhí)行。

到此這篇關(guān)于Linq之Distinct詳解的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論