ลบรายการซ้ำออกจากรายการ <T> ใน C #


487

ทุกคนมีวิธีที่รวดเร็วสำหรับการยกเลิกการทำรายการทั่วไปใน C # หรือไม่


4
คุณสนใจเกี่ยวกับลำดับขององค์ประกอบในผลลัพธ์หรือไม่ วิธีนี้จะยกเว้นโซลูชันบางอย่าง
พันเอก Panic

วิธีการแก้ปัญหาหนึ่งบรรทัด:ICollection<MyClass> withoutDuplicates = new HashSet<MyClass>(inputList);
แฮรัลด์ Coppoolse

คำตอบ:


227

บางทีคุณควรพิจารณาใช้HashSet

จากลิงก์ MSDN:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        HashSet<int> evenNumbers = new HashSet<int>();
        HashSet<int> oddNumbers = new HashSet<int>();

        for (int i = 0; i < 5; i++)
        {
            // Populate numbers with just even numbers.
            evenNumbers.Add(i * 2);

            // Populate oddNumbers with just odd numbers.
            oddNumbers.Add((i * 2) + 1);
        }

        Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
        DisplaySet(evenNumbers);

        Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
        DisplaySet(oddNumbers);

        // Create a new HashSet populated with even numbers.
        HashSet<int> numbers = new HashSet<int>(evenNumbers);
        Console.WriteLine("numbers UnionWith oddNumbers...");
        numbers.UnionWith(oddNumbers);

        Console.Write("numbers contains {0} elements: ", numbers.Count);
        DisplaySet(numbers);
    }

    private static void DisplaySet(HashSet<int> set)
    {
        Console.Write("{");
        foreach (int i in set)
        {
            Console.Write(" {0}", i);
        }
        Console.WriteLine(" }");
    }
}

/* This example produces output similar to the following:
 * evenNumbers contains 5 elements: { 0 2 4 6 8 }
 * oddNumbers contains 5 elements: { 1 3 5 7 9 }
 * numbers UnionWith oddNumbers...
 * numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }
 */

11
มันไม่น่าเชื่ออย่างรวดเร็ว ... 100.000 สายที่มีรายการใช้ 400s และ 8MB ram โซลูชันของฉันใช้เวลา 2.5s และ 28MB hashset ใช้เวลา 0.1s !!! และ ram 11MB
sasjaq

3
HashSet ไม่มีดัชนีดังนั้นจึงไม่สามารถใช้งานได้ตลอดเวลา ฉันต้องสร้างรายการใหญ่ครั้งหนึ่งโดยไม่ซ้ำกันแล้วใช้มันListViewในโหมดเสมือน มันเร็วมากในการสร้างHashSet<>ครั้งแรกแล้วแปลงเป็นList<>(เพื่อให้ListViewสามารถเข้าถึงรายการตามดัชนี) List<>.Contains()ช้าเกินไป
Sinatr

58
จะช่วยถ้ามีตัวอย่างของวิธีการใช้ hashset ในบริบทนี้
Nathan McKaskle

23
สิ่งนี้จะพิจารณาคำตอบได้อย่างไร มันเป็นลิงค์
mcont

2
HashSet นั้นยอดเยี่ยมในสถานการณ์ส่วนใหญ่ แต่ถ้าคุณมีวัตถุอย่าง DateTime มันจะทำการเปรียบเทียบโดยการอ้างอิงไม่ใช่ตามค่าดังนั้นคุณจะยังคงมีการซ้ำซ้อน
Jason McKindly

813

หากคุณใช้. Net 3+ คุณสามารถใช้ Linq

List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();

14
รหัสนั้นจะล้มเหลวในฐานะ. Distinct () ส่งคืน IEnumerable <T> คุณต้องเพิ่ม. ToList () ลงไป
ljs

วิธีการนี้สามารถใช้สำหรับรายการที่มีค่าอย่างง่ายเท่านั้น
โพลาริส

20
ไม่มันทำงานกับรายการที่มีวัตถุประเภทใดก็ได้ แต่คุณจะต้องแทนที่ตัวเปรียบเทียบเริ่มต้นสำหรับประเภทของคุณ เช่นเดียวกับ: การแทนที่สาธารณะบูลเท่ากับ (วัตถุ obj) {... }
BaBu

1
เป็นความคิดที่ดีที่จะแทนที่ ToString () และ GetHashCode () กับคลาสของคุณเพื่อให้สิ่งนี้ทำงานได้
B เซเว่น

2
คุณยังสามารถใช้แพ็คเกจ MoreLinQ Nuget ซึ่งมีวิธีการขยาย. DistinctBy () มีประโยชน์มาก
yu_ominae

178

เกี่ยวกับ:

var noDupes = list.Distinct().ToList();

ใน. net 3.5


ทำซ้ำรายการหรือไม่
darkgaze

1
@darkgaze นี่เพิ่งสร้างรายการใหม่ที่มีเฉพาะรายการที่ไม่ซ้ำกัน ดังนั้นรายการที่ซ้ำกันจะถูกลบออกและคุณจะเหลือรายการที่ทุกตำแหน่งมีวัตถุที่แตกต่างกัน
hexagod

ใช้งานได้กับรายการของรายการในรายการที่รหัสรายการซ้ำกันและต้องการรับรายการที่ไม่ซ้ำ
venkat

90

เพียงเริ่มต้น HashSet ด้วยรายการประเภทเดียวกัน:

var noDupes = new HashSet<T>(withDupes);

หรือถ้าคุณต้องการส่งคืนรายการ:

var noDupsList = new HashSet<T>(withDupes).ToList();

3
... และหากคุณต้องการList<T>ผลการใช้งานnew HashSet<T>(withDupes).ToList()
Tim Schmelter

47

เรียงลำดับจากนั้นตรวจสอบสองและสองถัดจากกันและกันเนื่องจากรายการที่ซ้ำกันจะรวมกันเป็นกลุ่ม

บางสิ่งเช่นนี้

list.Sort();
Int32 index = list.Count - 1;
while (index > 0)
{
    if (list[index] == list[index - 1])
    {
        if (index < list.Count - 1)
            (list[index], list[list.Count - 1]) = (list[list.Count - 1], list[index]);
        list.RemoveAt(list.Count - 1);
        index--;
    }
    else
        index--;
}

หมายเหตุ:

  • ทำการเปรียบเทียบจากหลังไปข้างหน้าเพื่อหลีกเลี่ยงรายการรีสอร์ทหลังจากการลบแต่ละครั้ง
  • ตัวอย่างนี้ใช้ Tuples มูลค่า C # เพื่อทำการแลกเปลี่ยนโดยแทนที่ด้วยรหัสที่เหมาะสมหากคุณไม่สามารถใช้มันได้
  • ผลลัพธ์สุดท้ายจะไม่ถูกจัดเรียงอีกต่อไป

1
หากฉันไม่เข้าใจผิดวิธีการส่วนใหญ่ที่กล่าวมาข้างต้นเป็นเพียงนามธรรมของงานประจำนี้ใช่ไหม? ฉันจะใช้แนวทางของคุณที่นี่ Lasse เพราะฉันคิดว่ามันเป็นภาพเคลื่อนไหวผ่านข้อมูลทางจิตใจ แต่ตอนนี้ฉันสนใจความแตกต่างของประสิทธิภาพระหว่างคำแนะนำบางอย่าง
เอียนแพทริคฮิวจ์

7
ใช้พวกเขาและเวลาพวกเขาวิธีเดียวที่จะมั่นใจ แม้แต่สัญกรณ์ Big-O จะไม่ช่วยคุณในการวัดประสิทธิภาพจริงเพียงแค่ความสัมพันธ์ที่มีผลต่อการเติบโต
Lasse V. Karlsen

1
ฉันชอบวิธีนี้มันพกพาสะดวกกว่าภาษาอื่น ๆ
Jerry Liang

10
อย่าทำอย่างนั้น มันช้ามาก RemoveAtเป็นการดำเนินการที่มีค่าใช้จ่ายสูงมากในวันที่List
Clément

1
Clémentถูกต้อง วิธีการกอบกู้สิ่งนี้คือการห่อสิ่งนี้ในวิธีที่ให้ผลตอบแทนกับตัวแจงนับและคืนค่าที่แตกต่างกันเท่านั้น หรือคุณสามารถคัดลอกค่าไปยังอาร์เรย์หรือรายการใหม่
JHubbard80

33

ฉันชอบที่จะใช้คำสั่งนี้:

List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId)
                                                 .GroupBy(s => s.City)
                                                 .Select(grp => grp.FirstOrDefault())
                                                 .OrderBy(s => s.City)
                                                 .ToList();

ฉันมีเขตข้อมูลเหล่านี้ในรายการของฉัน: รหัส, ชื่อร้านค้า, เมือง, รหัสไปรษณีย์ฉันต้องการแสดงรายการเมืองในรายการแบบเลื่อนลงซึ่งมีค่าซ้ำกัน วิธีแก้ปัญหา: จัดกลุ่มตามเมืองจากนั้นเลือกรายการแรกสำหรับรายการ

ฉันหวังว่ามันจะช่วย :)


31

มันใช้งานได้สำหรับฉัน เพียงใช้

List<Type> liIDs = liIDs.Distinct().ToList<Type>();

แทนที่ "Type" ด้วยประเภทที่คุณต้องการเช่น int


1
Distinct อยู่ใน Linq ไม่ใช่ System.Collections.Generic ตามที่รายงานโดยหน้า MSDN
Almo

5
คำตอบนี้ (2012) ดูเหมือนจะเป็นคำตอบเดียวกับอีกสองคำตอบในหน้านี้ที่มาจาก 2008
Jon Schneider

23

ตามที่ kronoz กล่าวใน. Net 3.5 คุณสามารถใช้ Distinct()คุณสามารถใช้

ใน. Net 2 คุณสามารถเลียนแบบได้:

public IEnumerable<T> DedupCollection<T> (IEnumerable<T> input) 
{
    var passedValues = new HashSet<T>();

    // Relatively simple dupe check alg used as example
    foreach(T item in input)
        if(passedValues.Add(item)) // True if item is new
            yield return item;
}

สิ่งนี้สามารถใช้เพื่อหักล้างการสะสมใด ๆ และจะคืนค่าในลำดับเดิม

ปกติแล้วมันจะเร็วกว่ามากในการกรองคอลเลกชัน (ทั้งคู่Distinct()และตัวอย่างนี้) กว่าจะเป็นการลบไอเท็มออกจากมัน


ปัญหาเกี่ยวกับวิธีการนี้แม้ว่าจะเป็น O (N ^ 2) -ish ซึ่งตรงกันข้ามกับ hashset แต่อย่างน้อยก็เห็นได้ชัดว่ากำลังทำอะไรอยู่
Tamas Czinege

1
@DrJokepu - จริง ๆ แล้วฉันไม่ได้ตระหนักว่าตัวHashSetสร้าง deduped ซึ่งทำให้ดีขึ้นสำหรับสถานการณ์ส่วนใหญ่ อย่างไรก็ตามสิ่งนี้จะรักษาลำดับการเรียงซึ่งHashSetไม่
Keith

1
HashSet <T> เปิดตัวใน 3.5
หนาม̈

1
@ ธ อร์นจริงเหรอ? ติดตามยากมาก ในกรณีที่คุณก็สามารถใช้Dictionary<T, object>แทนแทนที่.Containsด้วย.ContainsKeyและ.Add(item)ด้วย.Add(item, null)
คี ธ

@ Keith ตามการทดสอบของฉันHashSetคงลำดับในขณะที่Distinct()ไม่
Dennis T

13

วิธีการขยายอาจเป็นวิธีที่เหมาะสมในการไป ... บางสิ่งเช่นนี้:

public static List<T> Deduplicate<T>(this List<T> listToDeduplicate)
{
    return listToDeduplicate.Distinct().ToList();
}

จากนั้นเรียกสิ่งนี้เช่น:

List<int> myFilteredList = unfilteredList.Deduplicate();

11

ใน Java (ฉันถือว่า C # เหมือนกันมากหรือน้อย):

list = new ArrayList<T>(new HashSet<T>(list))

หากคุณต้องการที่จะกลายพันธุ์รายการเดิม:

List<T> noDupes = new ArrayList<T>(new HashSet<T>(list));
list.clear();
list.addAll(noDupes);

เพื่อรักษาคำสั่งซื้อเพียงแทนที่ HashSet ด้วย LinkedHashSet


5
ใน C # จะเป็น: List <T> noDupes = new List <T> (HashSet ใหม่ <T> (รายการ)); list.Clear (); list.AddRange (noDupes);
smohamed

ใน C # วิธีนี้ง่ายกว่า: var noDupes = new HashSet<T>(list); list.Clear(); list.AddRange(noDupes);:)
nawfal

10

สิ่งนี้ใช้เวลาที่แตกต่าง (องค์ประกอบโดยไม่ต้องทำซ้ำองค์ประกอบ) และแปลงเป็นรายการอีกครั้ง:

List<type> myNoneDuplicateValue = listValueWithDuplicate.Distinct().ToList();

9

ใช้ Linq ของสหภาพวิธี

หมายเหตุ: วิธีนี้ไม่จำเป็นต้องมีความรู้เกี่ยวกับ Linq นอกเหนือจากที่มีอยู่

รหัส

เริ่มต้นด้วยการเพิ่มสิ่งต่อไปนี้ที่ด้านบนของไฟล์คลาสของคุณ:

using System.Linq;

ตอนนี้คุณสามารถใช้สิ่งต่อไปนี้เพื่อลบรายการที่ซ้ำกันออกจากวัตถุที่เรียกว่าobj1:

obj1 = obj1.Union(obj1).ToList();

หมายเหตุ: เปลี่ยนชื่อobj1เป็นชื่อวัตถุของคุณ

มันทำงานอย่างไร

  1. คำสั่ง Union แสดงรายการหนึ่งในแต่ละรายการของวัตถุต้นทางสองรายการ เนื่องจาก obj1 เป็นทั้งวัตถุต้นทางสิ่งนี้จะลด obj1 ให้เป็นหนึ่งในแต่ละรายการ

  2. ToList()ส่งกลับรายการใหม่ นี่เป็นสิ่งจำเป็นเนื่องจากคำสั่ง Linq ต้องการUnionส่งคืนผลลัพธ์เป็นผลลัพธ์ IEnumerable แทนการแก้ไขรายการดั้งเดิมหรือส่งคืนรายการใหม่


7

เป็นวิธีการช่วยเหลือ (ไม่มี Linq):

public static List<T> Distinct<T>(this List<T> list)
{
    return (new HashSet<T>(list)).ToList();
}

ฉันคิดว่ามีความแตกต่างอยู่แล้ว นอกเหนือจากนั้น (ถ้าคุณเปลี่ยนวิธี) มันควรจะทำงาน
Andreas Reiff

6

หากคุณไม่สนใจเกี่ยวกับการสั่งซื้อคุณก็สามารถผลักรายการที่เป็นHashSetถ้าคุณไม่ต้องการที่จะรักษาความสงบเรียบร้อยที่คุณสามารถทำอะไรเช่นนี้

var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
    if (hs.Add(t))
        unique.Add(t);

หรือวิธี Linq:

var hs = new HashSet<T>();
list.All( x =>  hs.Add(x) );

แก้ไข:HashSetวิธีคือO(N)เวลาและO(N)พื้นที่ในขณะที่การเรียงลำดับและแล้วทำให้ไม่ซ้ำกัน (แนะนำโดย @ lassevkและอื่น ๆ ) เป็นO(N*lgN)เวลาและO(1)พื้นที่จึงไม่ให้ชัดเจนกับผม (ที่มันเป็นได้อย่างรวดเร็วก่อน) ว่าวิธีการเรียงลำดับรองลงมาคือ (ของฉัน ขอโทษสำหรับการลงคะแนนเสียงชั่วคราว ... )


6

นี่คือวิธีการขยายสำหรับการลบรายการที่ซ้ำกันที่อยู่ติดกันในแหล่งกำเนิด Call Sort () ก่อนและผ่านใน IComparer เดียวกัน สิ่งนี้ควรมีประสิทธิภาพมากกว่าเวอร์ชันของ Lasse V. Karlsen ที่เรียก RemoveAt ซ้ำ ๆ (ส่งผลให้เกิดการเคลื่อนย้ายหน่วยความจำบล็อกหลาย ๆ ครั้ง)

public static void RemoveAdjacentDuplicates<T>(this List<T> List, IComparer<T> Comparer)
{
    int NumUnique = 0;
    for (int i = 0; i < List.Count; i++)
        if ((i == 0) || (Comparer.Compare(List[NumUnique - 1], List[i]) != 0))
            List[NumUnique++] = List[i];
    List.RemoveRange(NumUnique, List.Count - NumUnique);
}

5

การติดตั้งแพ็คเกจMoreLINQผ่านทาง Nuget คุณสามารถแยกแยะรายการวัตถุได้โดยง่าย

IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 

3

อาจจะง่ายกว่าเพื่อให้แน่ใจว่าจะไม่เพิ่มรายการที่ซ้ำกันลงในรายการ

if(items.IndexOf(new_item) < 0) 
    items.add(new_item)

1
ขณะนี้ฉันกำลังทำสิ่งนี้อยู่ แต่ยิ่งคุณมีรายการตรวจสอบซ้ำซ้อนกันนานเท่าไหร่
Robert Strauch

ฉันมีปัญหาเดียวกันที่นี่ ฉันใช้List<T>.Containsวิธีนี้ทุกครั้ง แต่มีมากกว่า 1,000,000 รายการ กระบวนการนี้ทำให้ใบสมัครของฉันช้าลง ฉันใช้อันList<T>.Distinct().ToList<T>()แรกแทน
RPDeshaies

วิธีนี้ช้ามาก
darkgaze

3

คุณสามารถใช้ยูเนี่ยน

obj2 = obj1.Union(obj1).ToList();

7
คำอธิบายว่าทำไมมันถึงได้ผลจะทำให้คำตอบนี้ดีขึ้นอย่างแน่นอน
Igor B

2

อีกวิธีหนึ่งใน. Net 2.0

    static void Main(string[] args)
    {
        List<string> alpha = new List<string>();

        for(char a = 'a'; a <= 'd'; a++)
        {
            alpha.Add(a.ToString());
            alpha.Add(a.ToString());
        }

        Console.WriteLine("Data :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t); });

        alpha.ForEach(delegate (string v)
                          {
                              if (alpha.FindAll(delegate(string t) { return t == v; }).Count > 1)
                                  alpha.Remove(v);
                          });

        Console.WriteLine("Unique Result :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t);});
        Console.ReadKey();
    }

2

มีหลายวิธีในการแก้ไข - ปัญหาที่ซ้ำกันในรายการด้านล่างเป็นหนึ่งในนั้น:

List<Container> containerList = LoadContainer();//Assume it has duplicates
List<Container> filteredList = new  List<Container>();
foreach (var container in containerList)
{ 
  Container duplicateContainer = containerList.Find(delegate(Container checkContainer)
  { return (checkContainer.UniqueId == container.UniqueId); });
   //Assume 'UniqueId' is the property of the Container class on which u r making a search

    if(!containerList.Contains(duplicateContainer) //Add object when not found in the new class object
      {
        filteredList.Add(container);
       }
  }

เชียร์ Ravi Ganesan


2

นี่เป็นวิธีง่ายๆที่ไม่ต้องการ LINQ ที่อ่านยากหรือการเรียงลำดับรายการก่อนหน้า

   private static void CheckForDuplicateItems(List<string> items)
    {
        if (items == null ||
            items.Count == 0)
            return;

        for (int outerIndex = 0; outerIndex < items.Count; outerIndex++)
        {
            for (int innerIndex = 0; innerIndex < items.Count; innerIndex++)
            {
                if (innerIndex == outerIndex) continue;
                if (items[outerIndex].Equals(items[innerIndex]))
                {
                    // Duplicate Found
                }
            }
        }
    }

คุณสามารถควบคุมรายการที่ซ้ำกันได้มากขึ้นด้วยวิธีนี้ มากยิ่งขึ้นถ้าคุณมีฐานข้อมูลที่จะอัพเดท สำหรับ InnerIndex ทำไมไม่มีการเริ่มต้นจาก outerIndex + 1 แทนที่จะเริ่มจากการเริ่มต้นทุกครั้ง
Nolmë Informatique

2

คำตอบของ David J. เป็นวิธีการที่ดีไม่จำเป็นต้องมีวัตถุพิเศษการเรียงลำดับ ฯลฯ อย่างไรก็ตามสามารถปรับปรุงได้ใน:

for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)

ดังนั้นวงนอกจะไปด้านล่างสุดสำหรับรายการทั้งหมด แต่วงด้านในไปด้านล่าง "จนกว่าจะถึงตำแหน่งวงด้านนอก"

วนรอบด้านนอกทำให้แน่ใจว่ารายการทั้งหมดได้รับการประมวลผลแล้ววงด้านในจะค้นหารายการที่ซ้ำกันจริงซึ่งเกิดขึ้นได้เฉพาะในส่วนที่วงรอบนอกยังไม่ได้ประมวลผล

หรือถ้าคุณไม่ต้องการลงล่างสำหรับวงในคุณอาจเริ่มวนรอบด้านในที่ outerIndex + 1


2

คำตอบทั้งหมดคัดลอกรายการหรือสร้างรายการใหม่หรือใช้ฟังก์ชั่นช้าหรือเพียงช้าอย่างเจ็บปวด

เพื่อความเข้าใจของฉันนี่เป็นวิธีที่เร็วที่สุดและถูกที่สุดที่ฉันรู้ (เช่นกันซึ่งได้รับการสนับสนุนจากโปรแกรมเมอร์ที่มีประสบการณ์สูงซึ่งเชี่ยวชาญด้านการเพิ่มประสิทธิภาพฟิสิกส์ตามเวลาจริง)

// Duplicates will be noticed after a sort O(nLogn)
list.Sort();

// Store the current and last items. Current item declaration is not really needed, and probably optimized by the compiler, but in case it's not...
int lastItem = -1;
int currItem = -1;

int size = list.Count;

// Store the index pointing to the last item we want to keep in the list
int last = size - 1;

// Travel the items from last to first O(n)
for (int i = last; i >= 0; --i)
{
    currItem = list[i];

    // If this item was the same as the previous one, we don't want it
    if (currItem == lastItem)
    {
        // Overwrite last in current place. It is a swap but we don't need the last
       list[i] = list[last];

        // Reduce the last index, we don't want that one anymore
        last--;
    }

    // A new item, we store it and continue
    else
        lastItem = currItem;
}

// We now have an unsorted list with the duplicates at the end.

// Remove the last items just once
list.RemoveRange(last + 1, size - last - 1);

// Sort again O(n logn)
list.Sort();

ราคาสุดท้ายคือ:

nlogn + n + nlogn = n + 2nlogn = O (nlogn)ซึ่งค่อนข้างดี

หมายเหตุเกี่ยวกับ RemoveRange: เนื่องจากเราไม่สามารถกำหนดจำนวนรายการและหลีกเลี่ยงการใช้ funcions ลบได้ฉันไม่ทราบความเร็วของการดำเนินการนี้อย่างแน่นอน แต่ฉันคิดว่ามันเป็นวิธีที่เร็วที่สุด


2

หากคุณมีชั้นเรียนพ่วงProductและCustomerและเราต้องการที่จะลบรายการที่ซ้ำกันจากรายการของพวกเขา

public class Product
{
    public int Id { get; set; }
    public string ProductName { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string CustomerName { get; set; }

}

คุณต้องกำหนดคลาสทั่วไปในแบบฟอร์มด้านล่าง

public class ItemEqualityComparer<T> : IEqualityComparer<T> where T : class
{
    private readonly PropertyInfo _propertyInfo;

    public ItemEqualityComparer(string keyItem)
    {
        _propertyInfo = typeof(T).GetProperty(keyItem, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
    }

    public bool Equals(T x, T y)
    {
        var xValue = _propertyInfo?.GetValue(x, null);
        var yValue = _propertyInfo?.GetValue(y, null);
        return xValue != null && yValue != null && xValue.Equals(yValue);
    }

    public int GetHashCode(T obj)
    {
        var propertyValue = _propertyInfo.GetValue(obj, null);
        return propertyValue == null ? 0 : propertyValue.GetHashCode();
    }
}

จากนั้นคุณสามารถลบรายการที่ซ้ำกันในรายการของคุณ

var products = new List<Product>
            {
                new Product{ProductName = "product 1" ,Id = 1,},
                new Product{ProductName = "product 2" ,Id = 2,},
                new Product{ProductName = "product 2" ,Id = 4,},
                new Product{ProductName = "product 2" ,Id = 4,},
            };
var productList = products.Distinct(new ItemEqualityComparer<Product>(nameof(Product.Id))).ToList();

var customers = new List<Customer>
            {
                new Customer{CustomerName = "Customer 1" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
            };
var customerList = customers.Distinct(new ItemEqualityComparer<Customer>(nameof(Customer.Id))).ToList();

รหัสนี้ลบรายการที่ซ้ำกันโดยIdถ้าคุณต้องการลบรายการที่ซ้ำกันโดยคุณสมบัติอื่น ๆ คุณสามารถเปลี่ยนnameof(YourClass.DuplicateProperty) เหมือนกันnameof(Customer.CustomerName)แล้วลบรายการที่ซ้ำกันตามCustomerNameคุณสมบัติ


1
  public static void RemoveDuplicates<T>(IList<T> list )
  {
     if (list == null)
     {
        return;
     }
     int i = 1;
     while(i<list.Count)
     {
        int j = 0;
        bool remove = false;
        while (j < i && !remove)
        {
           if (list[i].Equals(list[j]))
           {
              remove = true;
           }
           j++;
        }
        if (remove)
        {
           list.RemoveAt(i);
        }
        else
        {
           i++;
        }
     }  
  }

1

การใช้งานง่ายที่เรียบง่าย:

public static List<PointF> RemoveDuplicates(List<PointF> listPoints)
{
    List<PointF> result = new List<PointF>();

    for (int i = 0; i < listPoints.Count; i++)
    {
        if (!result.Contains(listPoints[i]))
            result.Add(listPoints[i]);
        }

        return result;
    }

วิธีนี้ก็ช้าเช่นกัน สร้างรายการใหม่
darkgaze
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.