Remove duplicates from a List in C#

前端 未结 27 1812
广开言路
广开言路 2020-11-22 04:41

Anyone have a quick method for de-duplicating a generic List in C#?

相关标签:
27条回答
  • 2020-11-22 05:24
      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++;
            }
         }  
      }
    
    0 讨论(0)
  • 2020-11-22 05:25

    As kronoz said in .Net 3.5 you can use Distinct().

    In .Net 2 you could mimic it:

    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;
    }
    

    This could be used to dedupe any collection and will return the values in the original order.

    It's normally much quicker to filter a collection (as both Distinct() and this sample does) than it would be to remove items from it.

    0 讨论(0)
  • 2020-11-22 05:26

    A simple intuitive implementation:

    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;
        }
    
    0 讨论(0)
  • 2020-11-22 05:27

    Perhaps you should consider using a HashSet.

    From the MSDN link:

    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 }
     */
    
    0 讨论(0)
  • 2020-11-22 05:27

    Sort it, then check two and two next to each others, as the duplicates will clump together.

    Something like this:

    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--;
    }
    

    Notes:

    • Comparison is done from back to front, to avoid having to resort list after each removal
    • This example now uses C# Value Tuples to do the swapping, substitute with appropriate code if you can't use that
    • The end-result is no longer sorted
    0 讨论(0)
  • 2020-11-22 05:27

    Here's an extension method for removing adjacent duplicates in-situ. Call Sort() first and pass in the same IComparer. This should be more efficient than Lasse V. Karlsen's version which calls RemoveAt repeatedly (resulting in multiple block memory moves).

    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);
    }
    
    0 讨论(0)
提交回复
热议问题