C # 배열에서 중복을 어떻게 제거합니까?


209

string[]함수 호출에서 반환되는 C # 의 배열 로 작업하고 있습니다. Generic컬렉션에 캐스팅 할 수 는 있었지만 temp 배열을 사용하여 더 좋은 방법이 있는지 궁금했습니다.

C # 배열에서 중복을 제거하는 가장 좋은 방법은 무엇입니까?


4
고유 한 확장 방법을 사용하십시오.
kokos

과연. 배열이 이미 정렬되어 있으면 더 재미 있습니다.이 경우 O (n) 시간 내에 제자리에서 수행 할 수 있습니다.
David Airapetyan

@ Vitim.us 아니요. 제 경우에는 배열이 아니라 List <string>입니다. 나는 일을하는 어떤 대답도 받아들입니다. 아마도, 종이 위에해야한다는 충격 일 것입니다.
AngryHacker

답변:


427

LINQ 쿼리를 사용하여 다음을 수행 할 수 있습니다.

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

22
.Distinct(StringComparer.OrdinalIgnoreCase)대소 문자를 구분하지 않는 고유 한 문자열 집합을 얻는 것과 같이 IEqualityComparer를 매개 변수로 사용할 수 있습니다 .
justisb

Distinct가 요소의 원래 순서를 존중합니까?
asyrov

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

52

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

불행히도이 솔루션에는 해당 버전까지 HashSet이 추가되지 않았으므로 .NET Framework 3.5 이상이 필요합니다. LINQ의 기능인 array.Distinct ()를 사용할 수도 있습니다 .


11
이것은 아마도 원래 순서를 유지하지 못할 것입니다.
Hamish Grubijan

11

다음 테스트 및 작동 코드는 배열에서 중복을 제거합니다. 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 대신 힙을 사용할 수 있습니다
Neil Chowdhury

10

정렬해야 할 경우 중복을 제거하는 정렬을 구현할 수 있습니다.

그런 다음 하나의 돌로 두 마리의 새를 죽입니다.


7
정렬은 중복을 어떻게 제거합니까?
dan1

2
누가 이것을 투표 했습니까? 이것은 대답이 아닙니다. "팬케이크는 어떻게 만듭니 까?" "활에 재료를 넣고 섞는다."
Quarkly

9

이것은 솔루션을 얼마나 엔지니어링하고 싶은가에 달려 있습니다. 배열이 그렇게 크지 않고 목록 정렬에 신경 쓰지 않는다면 다음과 비슷한 것을 시도해보십시오.

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

4
ArrayList 대신 List를 사용해야합니다.
Doug S

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

3
이 질문에 대해 O (n * 2) 시간 복잡성을해서는 안됩니다.
dan1

2
병합 정렬을 사용해야합니다
Nick Gallimore

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

이것은 O (n ^ 2) 이며, 콤보에 채워질 짧은 목록에는 중요하지 않지만 큰 컬렉션에서 빠르게 문제가 될 수 있습니다.


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

다음은 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';
    }
}

위의 해시 / 링크 접근 방식은 일반적으로 실제 생활에서 사용하는 방법입니다. 그러나 인터뷰에서 그들은 일반적으로 해시를 배제하는 일정한 공간 또는 LINQ 를 사용하여 배제하는 내부 API가 없는 일정한 공간을두기를 원합니다 .


1
전체 목록을 저장해야 할 때 어떻게 O (1) 공간을 사용할 수 있습니까? 인플레 이스 정렬로 시작하면 훨씬 적은 코드로 O (nlogn) 시간 및 O (n) 메모리를 수행 할 수 있습니다.
Thomas Ahle

1
전체 목록을 저장한다고 생각하는 이유는 무엇입니까? 실제로 제자리에 있습니다. 그리고 질문의 조건은 아니지만 내 코드는 원래 문자열의 문자 순서를 유지합니다. 정렬하면 제거됩니다.
Sesh

1
내부 루프 ( strIn[j] == strIn[i])는 if 문을 고려하지 않는 한 문자열을 자체와 비교합니다.
3219

5

모든 문자열을 사전에 추가하고 나중에 Keys 속성을 가져옵니다. 이렇게하면 각각의 고유 한 문자열이 생성되지만 원래 입력과 동일한 순서는 아닙니다.

최종 결과가 원래 입력과 동일한 순서를 갖도록 요구하는 경우 각 문자열의 첫 번째 발생을 고려할 때 다음 알고리즘을 대신 사용하십시오.

  1. 목록 (최종 출력)과 사전 (중복 확인)을 갖습니다.
  2. 입력의 각 문자열에 대해 사전에 이미 존재하는지 확인하십시오.
  3. 그렇지 않은 경우 사전과 목록 모두에 추가하십시오.

마지막에는 목록에 각 고유 문자열의 첫 항목이 포함됩니다.

사전을 구성 할 때 문화와 같은 것을 고려하여 악센트 문자가있는 복제본을 올바르게 처리하십시오.


5

다음 코드는 이것이 최적의 솔루션이 아니지만 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);
            }
        }

5

간단한 해결책 :

using System.Linq;
...

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

5

중복 요소를 저장하지 않고 중복 추가 요청을 자동으로 무시하는 해시 세트 일 수 있습니다.

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

참고 : 테스트되지 않았습니다!

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

필요한 것을 할 수 있습니다 ...

편집 아아! 1 분도 안되는 시간에 강탈당했습니다!


롭은 당신을 이길 수 없었습니다. 그는 당신이 List를 사용하는 동안 ArrayList를 사용하고 있습니다. 버전이 더 좋습니다.
Doug S

4

아래를 테스트하고 작동합니다. 멋진 점은 문화에 민감한 검색도한다는 것입니다.

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

이 코드는 배열에서 중복 값을 100 % 제거합니다. [[[]]]을 사용했습니다. .... 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

일반 확장 방법 :

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

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

아래는 자바의 간단한 논리이며 배열의 요소를 두 번 순회하고 동일한 요소가 0을 할당하면 비교하는 요소의 색인을 건드리지 않습니다.

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
답을 설명 해주세요.
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;
         }
    }



}

이것은 매우 비효율적 인 방법입니다. 다른 답변을 살펴보고 그들이하는 일을보십시오.
Wai Ha Lee

0
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 문자열 .Join ( ",", XXX);

1 어레이를 분할하고 구별 [LINQ]을 사용하여 중복 제거 2 중복없이 다시 결합합니다.

코드 만 StackOverFlow의 텍스트를 읽지 못했습니다. 텍스트보다 더 의미가 있습니다.)


코드 전용 답변은 품질이 낮은 답변입니다. 이것이 왜 작동하는지에 대한 설명을 추가하십시오.
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
SO에 오신 것을 환영합니다. 이 코드 스 니펫이 해결책이 될 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자에게 질문에 대한 답변을 제공하고 있으며 해당 사람들이 귀하의 코드 제안 이유를 모를 수도 있습니다.
alan.elkin

유감스럽게도이 코드는 아무것도 제거하지 않으므로 중복을 제거하지 않습니다.
P_P

0

가장 좋은 방법은? 말할 것도없이, 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;
    }
}

거의 지점 무료. 어떻게? 작은 배열의 디버그 모드, Step Into (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;
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.