Làm cách nào để xóa các bản sao khỏi mảng C #?


209

Tôi đã làm việc với một string[]mảng trong C # được trả về từ một lệnh gọi hàm. Tôi có thể có thể sử dụng một Genericbộ sưu tập, nhưng tôi tự hỏi liệu có cách nào tốt hơn để làm nó không, có thể là sử dụng một mảng tạm thời.

Cách tốt nhất để loại bỏ các bản sao khỏi mảng C # là gì?


4
Sử dụng phương pháp mở rộng riêng biệt.
kokos

Thật. Sẽ vui hơn khi mảng đã được sắp xếp - trong trường hợp đó, nó có thể được thực hiện tại chỗ trong thời gian O (n).
David Airapetyan

@ Vitim.us Không. Trong trường hợp của tôi, nó thậm chí không phải là một mảng, mà là Danh sách <chuỗi>. Tôi chấp nhận bất kỳ câu trả lời nào làm công việc. Có lẽ, đó là một cú sốc khi phải làm điều đó trên giấy.
AngryHacker

Câu trả lời:


427

Bạn có thể có thể sử dụng truy vấn LINQ để làm điều này:

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

22
Lưu ý rằng bạn có thể sử dụng IEqualityComparer làm tham số, chẳng hạn như .Distinct(StringComparer.OrdinalIgnoreCase)để có được bộ chuỗi phân biệt không phân biệt chữ hoa chữ thường.
justĩa

Là khác biệt tôn vinh thứ tự ban đầu của các yếu tố?
asyrov

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

52

Đây là cách tiếp cận <chuỗi> Hashset:

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

Thật không may, giải pháp này cũng yêu cầu .NET framework 3.5 trở lên vì Hashset không được thêm cho đến phiên bản đó. Bạn cũng có thể sử dụng mảng.Distinc () , một tính năng của LINQ.


11
Điều này có lẽ sẽ không giữ được trật tự ban đầu.
Hamish Grubijan

11

Mã làm việc và thử nghiệm sau đây sẽ loại bỏ các bản sao khỏi một mảng. Bạn phải bao gồm không gian tên 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]);
}

Bạn có thể gói nó thành một chức năng nếu bạn muốn.


Điều này dường như là O (N ^ 2) ... Bạn có thể sử dụng một đống thay vì một ArrayList
Neil Chowdhury

10

Nếu bạn cần sắp xếp nó, thì bạn có thể thực hiện một loại cũng loại bỏ trùng lặp.

Giết hai con chim bằng một hòn đá.


7
Làm thế nào để sắp xếp loại bỏ trùng lặp?
dan1

2
Ai đã bình chọn điều này? Đây không phải là một câu trả lời. "Làm thế nào để tôi làm bánh kếp?" "Đặt một số thành phần trong một cây cung và trộn."
Quarkly

9

Điều này có thể phụ thuộc vào mức độ bạn muốn thiết kế giải pháp - nếu mảng sẽ không bao giờ lớn như vậy và bạn không quan tâm đến việc sắp xếp danh sách mà bạn có thể muốn thử một cái gì đó tương tự như sau:

    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
Bạn nên sử dụng List thay vì ArrayList.
Doug S

7

- Đây là câu hỏi phỏng vấn được hỏi mỗi lần. Bây giờ tôi đã thực hiện mã hóa của 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
Bạn không nên làm phức tạp thời gian O (n * 2) cho câu hỏi này.
dan1

2
Bạn nên sử dụng sắp xếp hợp nhất
Nick Gallolas

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

Đây là O (n ^ 2) , không quan trọng đối với một danh sách ngắn sẽ được nhồi vào một bộ kết hợp, nhưng có thể nhanh chóng là một vấn đề trong một bộ sưu tập lớ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

Dưới đây là cách tiếp cận O (n * n) sử dụng không gian 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';
    }
}

Các cách tiếp cận hash / linq ở trên là những gì bạn thường sử dụng trong cuộc sống thực. Tuy nhiên, trong các cuộc phỏng vấn, họ thường muốn đưa ra một số ràng buộc, ví dụ như không gian không đổi quy tắc băm hoặc không có api nội bộ - quy tắc sử dụng LINQ .


1
Làm thế nào nó có thể sử dụng không gian O (1), khi bạn phải lưu trữ toàn bộ danh sách? Bằng cách bắt đầu với một sắp xếp tại chỗ, bạn có thể thực hiện thời gian O (nlogn) và bộ nhớ O (n), với ít mã hơn nhiều.
Thomas Ahle

1
Điều gì khiến bạn nghĩ rằng nó đang lưu trữ toàn bộ danh sách? Nó thực sự đang làm tại chỗ. Và mặc dù không phải là một điều kiện trong câu hỏi, mã của tôi duy trì thứ tự các ký tự trong chuỗi gốc. Sắp xếp sẽ loại bỏ điều đó.
Sesh

1
Vòng lặp bên trong ( strIn[j] == strIn[i]) sẽ so sánh một chuỗi với chính nó trừ khi được tính bằng một câu lệnh if.
Người dùng3219

5

Thêm tất cả các chuỗi vào một từ điển và nhận thuộc tính Keys sau đó. Điều này sẽ tạo ra mỗi chuỗi duy nhất, nhưng không nhất thiết phải theo cùng thứ tự đầu vào ban đầu của bạn có chúng.

Nếu bạn yêu cầu kết quả cuối cùng có cùng thứ tự với đầu vào ban đầu, khi bạn xem xét lần xuất hiện đầu tiên của mỗi chuỗi, thay vào đó hãy sử dụng thuật toán sau:

  1. Có một danh sách (đầu ra cuối cùng) và một từ điển (để kiểm tra trùng lặp)
  2. Đối với mỗi chuỗi trong đầu vào, hãy kiểm tra xem nó có tồn tại trong từ điển không
  3. Nếu không, hãy thêm cả hai vào từ điển và vào danh sách

Cuối cùng, danh sách chứa lần xuất hiện đầu tiên của mỗi chuỗi duy nhất.

Hãy chắc chắn rằng bạn xem xét những thứ như văn hóa và như vậy khi xây dựng từ điển của bạn, để đảm bảo bạn xử lý các bản sao với các chữ cái có dấu chính xác.


5

Đoạn mã sau đây cố gắng loại bỏ các bản sao khỏi ArrayList mặc dù đây không phải là một giải pháp tối ưu. Tôi đã được hỏi câu hỏi này trong một cuộc phỏng vấn để loại bỏ các bản sao thông qua đệ quy và không sử dụng danh sách mảng thứ hai / 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

Giải pháp đơn giản:

using System.Linq;
...

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

5

Có thể hashset không lưu trữ các phần tử trùng lặp và âm thầm bỏ qua các yêu cầu để thêm trùng lặp.

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

LƯU Ý: KHÔNG được kiểm tra!

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

Có thể làm những gì bạn cần ...

EDIT Argh !!! đánh bại nó bằng cách cướp dưới một phút!


Rob đã không đánh bại bạn bất cứ điều gì. Anh ấy đang sử dụng ArrayList, trong khi bạn đang sử dụng Danh sách. Phiên bản của bạn tốt hơn.
Doug S

4

Đã thử nghiệm dưới đây và nó hoạt động. Điều tuyệt vời là nó cũng tìm kiếm văn hóa nhạy cảm

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

Mã này loại bỏ 100% giá trị trùng lặp khỏi một mảng [như tôi đã sử dụng [i]] ..... Bạn có thể chuyển đổi nó bằng bất kỳ ngôn ngữ OO nào ..... :)

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

Phương pháp mở rộng chung:

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

bạn có thể sử dụng Mã này khi làm việc với 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

Dưới đây là một logic đơn giản trong java, bạn duyệt qua các phần tử của mảng hai lần và nếu bạn thấy bất kỳ phần tử nào giống nhau, bạn gán 0 cho nó cộng với việc bạn không chạm vào chỉ mục của phần tử bạn đang so sánh.

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
giải thích câu trả lời của bạn
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;
         }
    }



}

Đây là một cách rất không hiệu quả để làm điều này. Có một cái nhìn vào các câu trả lời khác để xem những gì họ làm.
Wai Ha Lee

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

Kkk Không chắc đây là phù thủy hay chỉ là mã đẹp

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

2 chuỗi.Join (",", XXX);

1 Tách mảng và sử dụng Phân biệt [LINQ] để xóa các bản sao 2 Tham gia lại nó mà không cần các bản sao.

Xin lỗi tôi không bao giờ đọc văn bản trên StackOverFlow chỉ là mã. nó có ý nghĩa hơn văn bản;)


Câu trả lời chỉ có mã là câu trả lời chất lượng thấp. Thêm một số giải thích cho lý do tại sao điều này hoạt động.
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
Chào mừng đến với SO. Mặc dù đoạn mã này có thể là giải pháp, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
alan.elkin

Rất tiếc, mã này không xóa bất cứ thứ gì, vì vậy nó không xóa các bản sao.
P_P

0

Cách tốt nhất? Khó có thể nói, cách tiếp cận Hashset có vẻ nhanh, nhưng (tùy thuộc vào dữ liệu) sử dụng thuật toán sắp xếp (CountSort?) Có thể nhanh hơn nhiều.

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

Hầu như chi nhánh miễn phí. Làm sao? Chế độ gỡ lỗi, Bước vào (F11) với một mảng nhỏ: {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;
    }

Một giải pháp với hai vòng lặp lồng nhau có thể mất một thời gian, đặc biệt là đối với các mảng lớn hơn.

    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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.