¿Cómo elimino duplicados de una matriz de C #?


209

He estado trabajando con una string[]matriz en C # que se devuelve de una llamada de función. Posiblemente podría enviar a una Genericcolección, pero me preguntaba si había una mejor manera de hacerlo, posiblemente utilizando una matriz temporal.

¿Cuál es la mejor manera de eliminar duplicados de una matriz C #?


44
Use el método de extensión Distinct.
kokos

En efecto. Es más divertido cuando la matriz ya está ordenada; en ese caso, se puede hacer in situ en el tiempo O (n).
David Airapetyan

@ Vitim.us Nope. En mi caso, ni siquiera es una matriz, sino una Lista <cadena>. Acepto cualquier respuesta que haga el trabajo. Tal vez, es un shock tener que hacerlo en papel.
AngryHacker

Respuestas:


427

Posiblemente podría usar una consulta LINQ para hacer esto:

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

22
Tenga en cuenta que puede usar un IEqualityComparer como parámetro, por ejemplo, .Distinct(StringComparer.OrdinalIgnoreCase)para obtener un conjunto distinto de cadenas que no distingue entre mayúsculas y minúsculas.
justisb

¿Distinct honra el orden original de los elementos?
asyrov

@asyrov: desde MSDN:The Distinct() method returns an unordered sequence that contains no duplicate values.
tigrou

52

Aquí está el enfoque 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;
}

Desafortunadamente, esta solución también requiere .NET Framework 3.5 o posterior, ya que HashSet no se agregó hasta esa versión. También podría usar array.Distinct () , que es una característica de LINQ.


11
Esto probablemente no conservará el orden original.
Hamish Grubijan

11

El siguiente código probado y de trabajo eliminará los duplicados de una matriz. Debe incluir el espacio de nombres 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]);
}

Puede resumir esto en una función si lo desea.


Esto parece ser O (N ^ 2) ... Podría usar un montón en lugar de una ArrayList
Neil Chowdhury

10

Si necesita ordenarlo, puede implementar un orden que también elimine los duplicados.

Mata dos pájaros de un tiro, entonces.


77
¿Cómo ordena la eliminación de duplicados?
dan1

2
¿Quién votó esto? Esta no es una respuesta. "¿Cómo hago panqueques?" "Ponga algunos ingredientes en un arco y mezcle".
Quarkly

9

Esto puede depender de cuánto desea diseñar la solución: si la matriz nunca será tan grande y no le importa ordenar la lista, puede intentar algo similar a lo siguiente:

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

44
Debería usar List en lugar de ArrayList.
Doug S

7

- Esta es la pregunta de entrevista que se hace cada vez. Ahora hice su codificación.

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

3
No debe hacer una complejidad de tiempo O (n * 2) para esta pregunta.
dan1

2
Deberías usar el tipo de fusión
Nick Gallimore

7
List<String> myStringList = new List<string>();
foreach (string s in myStringArray)
{
    if (!myStringList.Contains(s))
    {
        myStringList.Add(s);
    }
}

Esto es O (n ^ 2) , lo que no importará para una lista corta que se incluirá en un combo, pero podría ser rápidamente un problema en una gran colección.


6
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 ");
    }
}

6

Aquí hay un enfoque O (n * n) que utiliza el espacio O (1) .

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

Los enfoques hash / linq anteriores son los que generalmente usaría en la vida real. Sin embargo, en las entrevistas, por lo general, quieren poner algunas restricciones, por ejemplo, un espacio constante que excluye el hash o ninguna API interna , que excluye el uso de LINQ .


1
¿Cómo puede usar el espacio O (1) cuando tiene que almacenar la lista completa? Al comenzar con una ordenación in situ, puede hacer O (nlogn) tiempo y O (n) memoria, con mucho menos código.
Thomas Ahle

1
¿Qué te hace pensar que está almacenando toda la lista? De hecho, está haciendo en el lugar. Y aunque no es una condición en la pregunta, mi código mantiene el orden de los caracteres en la cadena original. La clasificación eliminará eso.
Sesh

1
El bucle interno ( strIn[j] == strIn[i]) comparará una cadena consigo mismo a menos que se tenga en cuenta con una instrucción if.
Usuario3219

5

Agregue todas las cadenas a un diccionario y obtenga la propiedad Keys después. Esto producirá cada cadena única, pero no necesariamente en el mismo orden en que la entrada original las tenía.

Si necesita que el resultado final tenga el mismo orden que la entrada original, cuando considere la primera aparición de cada cadena, utilice el siguiente algoritmo:

  1. Tener una lista (salida final) y un diccionario (para verificar si hay duplicados)
  2. Para cada cadena en la entrada, verifique si ya existe en el diccionario
  3. De lo contrario, agréguelo tanto al diccionario como a la lista

Al final, la lista contiene la primera aparición de cada cadena única.

Asegúrate de considerar cosas como la cultura y demás al construir tu diccionario, para asegurarte de manejar correctamente los duplicados con letras acentuadas.


5

El siguiente fragmento de código intenta eliminar duplicados de una ArrayList, aunque esta no es una solución óptima. Me hicieron esta pregunta durante una entrevista para eliminar duplicados a través de la recursión, y sin usar una segunda lista de matrices / temp:

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

5

Solución simple:

using System.Linq;
...

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

5

Tal vez hashset que no almacena elementos duplicados e ignora silenciosamente las solicitudes para agregar duplicados.

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 + ",");
}

4

NOTA: ¡NO probado!

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

Podría hacer lo que necesita ...

EDITAR Argh !!! golpeado por robo por menos de un minuto!


Rob no te ganó en nada. Él está usando ArrayList, mientras que tú estás usando List. Tu versión es mejor.
Doug S

4

Probado a continuación y funciona. Lo bueno es que también hace una búsqueda sensible a la cultura

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


4

Este código elimina al 100% los valores duplicados de una matriz [ya que usé un [i]] ..... Puede convertirlo en cualquier lenguaje 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--;
        }
    }

}

4

Método de extensión genérico:

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

1

puede usar este código cuando trabaje con una 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]);

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

0

A continuación se muestra una lógica simple en java que atraviesa elementos de la matriz dos veces y si ve algún mismo elemento, le asigna cero y además no toca el índice del elemento que está comparando.

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

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

1
explica tu respuesta, por favor.
Badiparmagi

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



}

Esta es una forma muy ineficiente de hacer esto. Echa un vistazo a las otras respuestas para ver qué hacen.
Wai Ha Lee

0
strINvalues = "1,1,2,2,3,3,4,4";
strINvalues = string.Join(",", strINvalues .Split(',').Distinct().ToArray());
Debug.Writeline(strINvalues);

Kkk No estoy seguro si esto es brujería o simplemente un código hermoso

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

2 cuerdas. Unir (",", XXX);

1 Dividir la matriz y usar Distinct [LINQ] para eliminar duplicados. 2 Volver a unirla sin los duplicados.

Lo siento, nunca leí el texto en StackOverFlow solo el código. tiene más sentido que el texto;)


Las respuestas de solo código son respuestas de baja calidad. Agregue alguna explicación de por qué esto funciona.
Taslim Oseni

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

1
Bienvenido a SO. Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código.
alan.elkin

Lamentablemente, este código no elimina nada, por lo que no elimina duplicados.
P_P

0

¿La mejor manera? Difícil de decir, el enfoque HashSet parece rápido, pero (dependiendo de los datos) usar un algoritmo de clasificación (¿CountSort?) Puede ser mucho más rápido.

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

Casi sin rama. ¿Cómo? Modo de depuración, paso a paso (F11) con una pequeña matriz: {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;
    }

Una solución con dos bucles anidados puede llevar algún tiempo, especialmente para matrices más grandes.

    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;
    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.