¿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 #?

lomaxx
fuente
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();
Jeff Atwood
fuente
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.

Arcturus
fuente
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.

GateKiller
fuente
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.

Matthew Schinckel
fuente
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));
    }
rjzii
fuente
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();
        }
Muhammad Mubashir
fuente
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.

Will Dean
fuente
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 ");
    }
}
Pintu
fuente
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 .

Sesh
fuente
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.

Lasse V. Karlsen
fuente
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);
            }
        }
Vijay Swami
fuente
5

Solución simple:

using System.Linq;
...

public static int[] Distinct(int[] handles)
{
    return handles.ToList().Distinct().ToArray();
}
Fábio Delboni
fuente
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 + ",");
}
lukaszk
fuente
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!

ZombiOvejas
fuente
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

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

}
Salman Ramzan
fuente
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;
        }
    }
}
Ali Bayat
fuente
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]);
reza akhlaghi
fuente
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;
}
Harry Martyrossian
fuente
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;
            }
        }
    }
}
Papasani Mohansrinivas
fuente
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;
        }
Arie Yehieli
fuente
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;
         }
    }



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

Kudakwashe Mafutah
fuente
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--;
                }
            }
        }
Swathi Sriramaneni
fuente
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;
    }
PÁGINAS
fuente