【问题标题】:How do I remove duplicates from a C# array?如何从 C# 数组中删除重复项?
【发布时间】:2010-09-05 19:09:00
【问题描述】:

我一直在使用 C# 中的 string[] 数组,该数组从函数调用中返回。我可能会强制转换为 Generic 集合,但我想知道是否有更好的方法可以做到这一点,可能是使用临时数组。

从 C# 数组中删除重复项的最佳方法是什么?

【问题讨论】:

  • 使用 Distinct 扩展方法。
  • 确实如此。当数组已经排序时会更有趣——在这种情况下,它可以在 O(n) 时间内就地完成。
  • @Vitim.us 不。在我的例子中,它甚至不是一个数组,而是一个 List。我接受任何可以完成工作的答案。也许,不得不在纸上做这件事令人震惊。
  • 比...更好的方法?转换为通用集合的想法是什么?无论哪种方式,对于任何想要添加另一个答案的人来说:请记住,问题不是像几乎每个人那样“a 删除重复项的方法”。任何答案都应考虑时间复杂度并显示基准。到目前为止,只有两个答案做了认真的尝试。

标签: c# arrays duplicates


【解决方案1】:

您可以使用 LINQ 查询来执行此操作:

int[] s = { 1, 2, 3, 3, 4};
int[] q = s.Distinct().ToArray();

【讨论】:

  • 请注意,您可以使用 IEqualityComparer 作为参数,例如 .Distinct(StringComparer.OrdinalIgnoreCase) 来获取不区分大小写的不同字符串集。
  • Distinct 是否尊重元素的原始顺序?
  • @asyrov:来自 MSDN:The Distinct() method returns an unordered sequence that contains no duplicate values.
  • 是什么让这成为“最佳方式”?
【解决方案2】:

这是HashSet<string> 方法:

public static string[] RemoveDuplicates(string[] s)
{
    HashSet<string> set = new HashSet<string>(s);
    string[] result = new string[set.Count];
    set.CopyTo(result);
    return result;
}

不幸的是,此解决方案还需要 .NET 框架 3.5 或更高版本,因为直到该版本才添加 HashSet。您也可以使用array.Distinct(),这是 LINQ 的一个特性。

【讨论】:

  • 这可能不会保留原来的顺序。
【解决方案3】:

以下经过测试且工作正常的代码将从数组中删除重复项。您必须包含 System.Collections 命名空间。

string[] sArray = {"a", "b", "b", "c", "c", "d", "e", "f", "f"};
var sList = new ArrayList();

for (int i = 0; i < sArray.Length; i++) {
    if (sList.Contains(sArray[i]) == false) {
        sList.Add(sArray[i]);
    }
}

var sNew = sList.ToArray();

for (int i = 0; i < sNew.Length; i++) {
    Console.Write(sNew[i]);
}

如果你愿意,你可以把它包装成一个函数。

【讨论】:

  • 这似乎是 O(N^2)... 你可以使用堆而不是 ArrayList
【解决方案4】:

如果您需要对其进行排序,那么您可以实现一个同时删除重复项的排序。

那么,用一块石头杀死两只鸟。

【讨论】:

  • 排序如何去除重复项?
  • 谁投了这个票?这不是答案。 “我怎么做煎饼?” “把一些原料放在一个弓上混合。”
  • 正确,这确实不是一个答案。我相信这是在 StackOverflow cmets 之前发表的评论。当关于 SO 的问题少于 10k 时,会提出此问题。
【解决方案5】:

这可能取决于您想设计多少解决方案 - 如果数组永远不会那么大并且您不关心对列表进行排序,您可能想尝试类似以下的操作:

    public string[] RemoveDuplicates(string[] myList) {
        System.Collections.ArrayList newList = new System.Collections.ArrayList();

        foreach (string str in myList)
            if (!newList.Contains(str))
                newList.Add(str);
        return (string[])newList.ToArray(typeof(string));
    }

【讨论】:

  • 你应该使用 List 而不是 ArrayList。
【解决方案6】:
List<String> myStringList = new List<string>();
foreach (string s in myStringArray)
{
    if (!myStringList.Contains(s))
    {
        myStringList.Add(s);
    }
}

这是 O(n^2),这对于将被塞入组合中的短列表无关紧要,但可能很快成为大集合的问题。

【讨论】:

    【解决方案7】:

    -- 这是面试问题,每次都会问。现在我完成了它的编码。

    static void Main(string[] args)
    {    
                int[] array = new int[] { 4, 8, 4, 1, 1, 4, 8 };            
                int numDups = 0, prevIndex = 0;
    
                for (int i = 0; i < array.Length; i++)
                {
                    bool foundDup = false;
                    for (int j = 0; j < i; j++)
                    {
                        if (array[i] == array[j])
                        {
                            foundDup = true;
                            numDups++; // Increment means Count for Duplicate found in array.
                            break;
                        }                    
                    }
    
                    if (foundDup == false)
                    {
                        array[prevIndex] = array[i];
                        prevIndex++;
                    }
                }
    
                // Just Duplicate records replce by zero.
                for (int k = 1; k <= numDups; k++)
                {               
                    array[array.Length - k] = '\0';             
                }
    
    
                Console.WriteLine("Console program for Remove duplicates from array.");
                Console.Read();
            }
    

    【讨论】:

    • 你不应该为这个问题做 O(n*2) 时间复杂度。
    • 你应该使用归并排序
    【解决方案8】:

    这是一个使用 O(1) 空间的 O(n*n) 方法。

    void removeDuplicates(char* strIn)
    {
        int numDups = 0, prevIndex = 0;
        if(NULL != strIn && *strIn != '\0')
        {
            int len = strlen(strIn);
            for(int i = 0; i < len; i++)
            {
                bool foundDup = false;
                for(int j = 0; j < i; j++)
                {
                    if(strIn[j] == strIn[i])
                    {
                        foundDup = true;
                        numDups++;
                        break;
                    }
                }
    
                if(foundDup == false)
                {
                    strIn[prevIndex] = strIn[i];
                    prevIndex++;
                }
            }
    
            strIn[len-numDups] = '\0';
        }
    }
    

    上面的 hash/linq 方法是您在现实生活中通常使用的方法。然而,在采访中,他们通常希望设置一些限制条件,例如排除散列或没有内部 api 的常量空间 - 排除使用 LINQ

    【讨论】:

    • 当您必须存储整个列表时,它怎么能使用 O(1) 空间?从就地排序开始,您可以用更少的代码完成 O(nlogn) 时间和 O(n) 内存。
    • 是什么让您认为它存储了整个列表?它确实在原地进行。虽然不是问题中的条件,但我的代码保持了原始字符串中字符的顺序。排序将删除它。
    • 内部循环 (strIn[j] == strIn[i]) 会将字符串与自身进行比较,除非使用 if 语句。
    【解决方案9】:
    protected void Page_Load(object sender, EventArgs e)
    {
        string a = "a;b;c;d;e;v";
        string[] b = a.Split(';');
        string[] c = b.Distinct().ToArray();
    
        if (b.Length != c.Length)
        {
            for (int i = 0; i < b.Length; i++)
            {
                try
                {
                    if (b[i].ToString() != c[i].ToString())
                    {
                        Response.Write("Found duplicate " + b[i].ToString());
                        return;
                    }
                }
                catch (Exception ex)
                {
                    Response.Write("Found duplicate " + b[i].ToString());
                    return;
                }
            }              
        }
        else
        {
            Response.Write("No duplicate ");
        }
    }
    

    【讨论】:

      【解决方案10】:

      将所有字符串添加到字典中,然后获取 Keys 属性。这将产生每个唯一的字符串,但不一定按照您原始输入的顺序。

      如果您要求最终结果与原始输入具有相同的顺序,当您考虑每个字符串的第一次出现时,请改用以下算法:

      1. 有一个列表(最终输出)和一个字典(检查重复项)
      2. 对于输入中的每个字符串,检查它是否已经存在于字典中
      3. 如果没有,请将其添加到字典和列表中

      最后,列表包含每个唯一字符串的第一次出现。

      确保在构建字典时考虑文化等因素,以确保正确处理带有重音字母的重复项。

      【讨论】:

        【解决方案11】:

        以下代码尝试从 ArrayList 中删除重复项,尽管这不是最佳解决方案。我在一次采访中被问到这个问题,通过递归删除重复项,并且不使用第二个/临时数组列表:

        private void RemoveDuplicate() 
        {
        
        ArrayList dataArray = new ArrayList(5);
        
                    dataArray.Add("1");
                    dataArray.Add("1");
                    dataArray.Add("6");
                    dataArray.Add("6");
                    dataArray.Add("6");
                    dataArray.Add("3");
                    dataArray.Add("6");
                    dataArray.Add("4");
                    dataArray.Add("5");
                    dataArray.Add("4");
                    dataArray.Add("1");
        
                    dataArray.Sort();
        
                    GetDistinctArrayList(dataArray, 0);
        }
        
        private void GetDistinctArrayList(ArrayList arr, int idx)
        
        {
        
                    int count = 0;
        
                    if (idx >= arr.Count) return;
        
                    string val = arr[idx].ToString();
                    foreach (String s in arr)
                    {
                        if (s.Equals(arr[idx]))
                        {
                            count++;
                        }
                    }
        
                    if (count > 1)
                    {
                        arr.Remove(val);
                        GetDistinctArrayList(arr, idx);
                    }
                    else
                    {
                        idx += 1;
                        GetDistinctArrayList(arr, idx);
                    }
                }
        

        【讨论】:

          【解决方案12】:

          简单的解决方案:

          using System.Linq;
          ...
          
          public static int[] Distinct(int[] handles)
          {
              return handles.ToList().Distinct().ToArray();
          }
          

          【讨论】:

            【解决方案13】:

            也许 hashset 不存储重复元素并默默地忽略添加请求 重复。

            static void Main()
            {
                string textWithDuplicates = "aaabbcccggg";     
            
                Console.WriteLine(textWithDuplicates.Count());  
                var letters = new HashSet<char>(textWithDuplicates);
                Console.WriteLine(letters.Count());
            
                foreach (char c in letters) Console.Write(c);
                Console.WriteLine("");
            
                int[] array = new int[] { 12, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
            
                Console.WriteLine(array.Count());
                var distinctArray = new HashSet<int>(array);
                Console.WriteLine(distinctArray.Count());
            
                foreach (int i in distinctArray) Console.Write(i + ",");
            }
            

            【讨论】:

              【解决方案14】:

              注意:未经测试!

              string[] test(string[] myStringArray)
              {
                  List<String> myStringList = new List<string>();
                  foreach (string s in myStringArray)
                  {
                      if (!myStringList.Contains(s))
                      {
                          myStringList.Add(s);
                      }
                  }
                  return myStringList.ToString();
              }
              

              可能会做你需要的......

              编辑啊!!!不到一分钟就被抢了!

              【讨论】:

              • Rob 并没有打败你。他使用 ArrayList,而您使用 List。你的版本更好。
              【解决方案15】:

              测试了以下内容并且可以正常工作。很酷的是它也可以进行文化敏感搜索

              class RemoveDuplicatesInString
              {
                  public static String RemoveDups(String origString)
                  {
                      String outString = null;
                      int readIndex = 0;
                      CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo;
              
              
                      if(String.IsNullOrEmpty(origString))
                      {
                          return outString;
                      }
              
                      foreach (var ch in origString)
                      {
                          if (readIndex == 0)
                          {
                              outString = String.Concat(ch);
                              readIndex++;
                              continue;
                          }
              
                          if (ci.IndexOf(origString, ch.ToString().ToLower(), 0, readIndex) == -1)
                          {
                              //Unique char as this char wasn't found earlier.
                              outString = String.Concat(outString, ch);                   
                          }
              
                          readIndex++;
              
                      }
              
              
                      return outString;
                  }
              
              
                  static void Main(string[] args)
                  {
                      String inputString = "aAbcefc";
                      String outputString;
              
                      outputString = RemoveDups(inputString);
              
                      Console.WriteLine(outputString);
                  }
              

              }

              --AptSenSDET

              【讨论】:

                【解决方案16】:

                此代码 100% 从数组中删除重复值[就像我使用 a[i]] .....您可以将其转换为任何 OO 语言..... :)

                for(int i=0;i<size;i++)
                {
                    for(int j=i+1;j<size;j++)
                    {
                        if(a[i] == a[j])
                        {
                            for(int k=j;k<size;k++)
                            {
                                 a[k]=a[k+1];
                            }
                            j--;
                            size--;
                        }
                    }
                
                }
                

                【讨论】:

                  【解决方案17】:

                  通用扩展方法:

                  public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
                  {
                      if (source == null)
                          throw new ArgumentNullException(nameof(source));
                  
                      HashSet<TSource> set = new HashSet<TSource>(comparer);
                      foreach (TSource item in source)
                      {
                          if (set.Add(item))
                          {
                              yield return item;
                          }
                      }
                  }
                  

                  【讨论】:

                    【解决方案18】:

                    您可以在使用 ArrayList 时使用此代码

                    ArrayList arrayList;
                    //Add some Members :)
                    arrayList.Add("ali");
                    arrayList.Add("hadi");
                    arrayList.Add("ali");
                    
                    //Remove duplicates from array
                      for (int i = 0; i < arrayList.Count; i++)
                        {
                           for (int j = i + 1; j < arrayList.Count ; j++)
                               if (arrayList[i].ToString() == arrayList[j].ToString())
                                     arrayList.Remove(arrayList[j]);
                    

                    【讨论】:

                      【解决方案19】:

                      下面是一个简单的java逻辑,你遍历数组的元素两次,如果你看到任何相同的元素,你给它分配零,而且你不接触你正在比较的元素的索引。

                      import java.util.*;
                      class removeDuplicate{
                      int [] y ;
                      
                      public removeDuplicate(int[] array){
                          y=array;
                      
                          for(int b=0;b<y.length;b++){
                              int temp = y[b];
                              for(int v=0;v<y.length;v++){
                                  if( b!=v && temp==y[v]){
                                      y[v]=0;
                                  }
                              }
                          }
                      }
                      

                      【讨论】:

                        【解决方案20】:
                        public static int RemoveDuplicates(ref int[] array)
                        {
                            int size = array.Length;
                        
                            // if 0 or 1, return 0 or 1:
                            if (size  < 2) {
                                return size;
                            }
                        
                            int current = 0;
                            for (int candidate = 1; candidate < size; ++candidate) {
                                if (array[current] != array[candidate]) {
                                    array[++current] = array[candidate];
                                }
                            }
                        
                            // index to count conversion:
                            return ++current;
                        }
                        

                        【讨论】:

                          【解决方案21】:

                          最好的方法?很难说,HashSet 方法看起来很快, 但是(取决于数据)使用排序算法(CountSort?) 可以更快。

                          using System;
                          using System.Collections.Generic;
                          using System.Linq;
                          class Program
                          {
                              static void Main()
                              {
                                  Random r = new Random(0); int[] a, b = new int[1000000];
                                  for (int i = b.Length - 1; i >= 0; i--) b[i] = r.Next(b.Length);
                                  a = new int[b.Length]; Array.Copy(b, a, b.Length);
                                  a = dedup0(a); Console.WriteLine(a.Length);
                                  a = new int[b.Length]; Array.Copy(b, a, b.Length);
                                  var w = System.Diagnostics.Stopwatch.StartNew();
                                  a = dedup0(a); Console.WriteLine(w.Elapsed); Console.Read();
                              }
                          
                              static int[] dedup0(int[] a)  // 48 ms  
                              {
                                  return new HashSet<int>(a).ToArray();
                              }
                          
                              static int[] dedup1(int[] a)  // 68 ms
                              {
                                  Array.Sort(a); int i = 0, j = 1, k = a.Length; if (k < 2) return a;
                                  while (j < k) if (a[i] == a[j]) j++; else a[++i] = a[j++];
                                  Array.Resize(ref a, i + 1); return a;
                              }
                          
                              static int[] dedup2(int[] a)  //  8 ms
                              {
                                  var b = new byte[a.Length]; int c = 0;
                                  for (int i = 0; i < a.Length; i++) 
                                      if (b[a[i]] == 0) { b[a[i]] = 1; c++; }
                                  a = new int[c];
                                  for (int j = 0, i = 0; i < b.Length; i++) if (b[i] > 0) a[j++] = i;
                                  return a;
                              }
                          }
                          

                          几乎没有分支。如何?调试模式,使用小数组进入 (F11):{1,3,1,1,0}

                              static int[] dedupf(int[] a)  //  4 ms
                              {
                                  if (a.Length < 2) return a;
                                  var b = new byte[a.Length]; int c = 0, bi, ai, i, j;
                                  for (i = 0; i < a.Length; i++)
                                  { ai = a[i]; bi = 1 ^ b[ai]; b[ai] |= (byte)bi; c += bi; }
                                  a = new int[c]; i = 0; while (b[i] == 0) i++; a[0] = i++;
                                  for (j = 0; i < b.Length; i++) a[j += bi = b[i]] += bi * i; return a;
                              }
                          

                          具有两个嵌套循环的解决方案可能需要一些时间, 特别是对于较大的数组。

                              static int[] dedup(int[] a)
                              {
                                  int i, j, k = a.Length - 1;
                                  for (i = 0; i < k; i++)
                                      for (j = i + 1; j <= k; j++) if (a[i] == a[j]) a[j--] = a[k--];
                                  Array.Resize(ref a, k + 1); return a;
                              }
                          

                          【讨论】:

                            【解决方案22】:
                              private static string[] distinct(string[] inputArray)
                                    {
                                        bool alreadyExists;
                                        string[] outputArray = new string[] {};
                            
                                        for (int i = 0; i < inputArray.Length; i++)
                                        {
                                            alreadyExists = false;
                                            for (int j = 0; j < outputArray.Length; j++)
                                            {
                                                if (inputArray[i] == outputArray[j])
                                                    alreadyExists = true;
                                            }
                                                    if (alreadyExists==false)
                                                    {
                                                        Array.Resize<string>(ref outputArray, outputArray.Length + 1);
                                                        outputArray[outputArray.Length-1] = inputArray[i];
                                                    }
                                        }
                                        return outputArray;
                                    }
                            

                            【讨论】:

                            • 请解释一下你的答案。
                            【解决方案23】:
                            int size = a.Length;
                                    for (int i = 0; i < size; i++)
                                    {
                                        for (int j = i + 1; j < size; j++)
                                        {
                                            if (a[i] == a[j])
                                            {
                                                for (int k = j; k < size; k++)
                                                {
                                                    if (k != size - 1)
                                                    {
                                                        int temp = a[k];
                                                        a[k] = a[k + 1];
                                                        a[k + 1] = temp;
                            
                                                    }
                                                }
                                                j--;
                                                size--;
                                            }
                                        }
                                    }
                            

                            【讨论】:

                            • 欢迎来到 SO。虽然这段代码 sn-p 可能是解决方案,但包含解释确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
                            • 很遗憾这段代码没有删除任何东西,所以它没有删除重复项。
                            • 遗憾的是,编码器也没有删除任何东西:)
                            【解决方案24】:

                            所以我在做一个面试环节,并得到了同样的问题来分类和区分

                            static void Sort()
                                {
                                    try
                                    {
                                        int[] number = new int[Convert.ToInt32(Console.ReadLine())];
                                        for (int i = 0; i < number.Length; i++)
                                        {
                                            number[i] = Convert.ToInt32(Console.ReadLine());
                                        }
                                        Array.Sort(number);
                                        int[] num = number.Distinct().ToArray();
                                        for (int i = 0; i < num.Length; i++)
                                        {
                                            Console.WriteLine(num[i]);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine(ex);
                                    }
                                    Console.Read();
                                }
                            

                            【讨论】:

                              【解决方案25】:
                              using System;
                              using System.Collections.Generic;
                              using System.Linq;
                              
                              
                              namespace Rextester
                              {
                                  public class Program
                                  {
                                      public static void Main(string[] args)
                                      {
                                           List<int> listofint1 = new List<int> { 4, 8, 4, 1, 1, 4, 8 };
                                         List<int> updatedlist= removeduplicate(listofint1);
                                          foreach(int num in updatedlist)
                                             Console.WriteLine(num);
                                      }
                              
                              
                                      public static List<int> removeduplicate(List<int> listofint)
                                       {
                                           List<int> listofintwithoutduplicate= new List<int>();
                              
                              
                                            foreach(var num in listofint)
                                               {
                                                if(!listofintwithoutduplicate.Any(p=>p==num))
                                                      {
                                                        listofintwithoutduplicate.Add(num);
                                                      }
                                                }
                                           return listofintwithoutduplicate;
                                       }
                                  }
                              
                              
                              
                              }
                              

                              【讨论】:

                              • 这是一种非常低效的方法。看看其他答案,看看他们做了什么。
                              【解决方案26】:
                              strINvalues = "1,1,2,2,3,3,4,4";
                              strINvalues = string.Join(",", strINvalues .Split(',').Distinct().ToArray());
                              Debug.Writeline(strINvalues);
                              

                              Kkk 不确定这是巫术还是漂亮的代码

                              1 strINvalues .Split(',').Distinct().ToArray()

                              2 string.Join(",", XXX);

                              1 拆分数组并使用 Distinct [LINQ] 删除重复项 2 在没有重复的情况下加入它。

                              对不起,我从来没有读过 StackOverFlow 上的文字,只是代码。它比文字更有意义;)

                              【讨论】:

                              • 纯代码答案是低质量的答案。添加一些解释为什么会这样。
                              • 问题是“从 C# 数组中删除重复项的最佳方法是什么?”。你不回答这个问题。
                              【解决方案27】:

                              使用 Distinct 和 StringComparer.InvariantCultureIgnoreCase 删除重复并忽略区分大小写

                              string[] array = new string[] { "A", "a", "b", "B", "a", "C", "c", "C", "A", "1" };
                              var r = array.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();
                              Console.WriteLine(r.Count); // return 4 items
                              

                              【讨论】:

                              • 问题是“从 C# 数组中删除重复项的最佳方法是什么?”。你不回答这个问题。
                              • 再次阅读问题“如何从 C# 数组中删除重复项?”
                              【解决方案28】:

                              在下面找到答案。

                              class Program
                              {
                                  static void Main(string[] args)
                                  {
                                      var nums = new int[] { 1, 4, 3, 3, 3, 5, 5, 7, 7, 7, 7, 9, 9, 9 };
                                      var result = removeDuplicates(nums);
                                      foreach (var item in result)
                                      {
                                          Console.WriteLine(item);
                                      }
                                  }
                                  static int[] removeDuplicates(int[] nums)
                                  {
                                      nums = nums.ToList().OrderBy(c => c).ToArray();
                                      int j = 1;
                                      int i = 0;
                                      int stop = 0;
                                      while (j < nums.Length)
                                      {
                                          if (nums[i] != nums[j])
                                          {
                                              nums[i + 1] = nums[j];
                                              stop = i + 2;
                                              i++;
                                          }
                                          j++;
                                      }
                                      nums = nums.Take(stop).ToArray();
                                      return nums;
                                  }
                              }
                              

                              只是基于我刚刚解决的测试的一点贡献,可能对这里的其他顶级贡献者有帮助并愿意改进。 以下是我所做的事情:

                              1. 我使用了 OrderBy,它允许我使用 LINQ 从小到大对项目进行排序或排序
                              2. 然后我将其转换回数组,然后将其重新分配回主数据源
                              3. 然后我将数组右侧的 j 初始化为 1,将数组左侧的 i 初始化为 0,我还将我要停止的位置初始化为 0。李>
                              4. 我使用 while 循环从一个位置到另一个位置从左到右递增数组,对于每个递增,停止位置是 i + 2 的当前值,我稍后将使用它来截断重复的数组。
                              5. 然后,我通过从 if 语句从左到右移动以及在 if 语句之外从右到右移动来递增,直到我遍历数组的整个值。
                              6. 然后我从第一个元素到停止位置,该位置成为最后一个 i 索引加 2。这样我就可以从 int 数组中删除所有重复项。然后重新分配。

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2019-03-15
                                • 2021-02-20
                                • 1970-01-01
                                • 2017-06-21
                                • 2022-01-03
                                相关资源
                                最近更新 更多