Я работал с массивом string[] на C#, который возвращается из вызова функции. Я мог бы привести к коллекции Generic, но мне было интересно, есть ли лучший способ сделать это, возможно, используя временный массив.
Как лучше всего удалить дубликаты из массива C#?
@ Vitim.us Нет. В моем случае это даже не массив, а List
Используйте метод расширения Distinct.





Если вам нужно отсортировать его, вы можете реализовать сортировку, которая также удаляет дубликаты.
Значит, убивает двух зайцев одним выстрелом.
Как сортировка удаляет дубликаты?
Кто проголосовал за это? Это не ответ. "Как мне приготовить блины?" «Положите ингредиенты в лук и перемешайте».
Верно, это действительно не ответ. Думаю, это был комментарий, сделанный до комментариев StackOverflow имел. Этот вопрос задавали, когда на SO было меньше 10 тысяч вопросов.
Для этого вы могли бы использовать запрос 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.
Добавьте все строки в словарь, а затем получите свойство Keys. Это создаст каждую уникальную строку, но не обязательно в том же порядке, в котором они были в исходном вводе.
Если вам требуется, чтобы конечный результат имел тот же порядок, что и исходный ввод, при рассмотрении первого появления каждой строки вместо этого используйте следующий алгоритм:
В конце список содержит первое появление каждой уникальной строки.
Убедитесь, что вы учитываете такие вещи, как культура и тому подобное, когда составляете свой словарь, чтобы убедиться, что вы правильно обрабатываете дубликаты с акцентированными буквами.
Следующий протестированный и рабочий код удалит дубликаты из массива. Вы должны включить пространство имен 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
Это может зависеть от того, насколько вы хотите разработать решение - если массив никогда не будет таким большим и вам не нужно сортировать список, вы можете попробовать что-то подобное следующему:
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.
ПРИМЕЧАНИЕ: НЕ проверено!
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();
}
Сделай то, что тебе нужно ...
РЕДАКТИРОВАТЬ Ага !!! избит грабителем менее чем за минуту!
Роб тебя ни в чем не бил. Он использует ArrayList, а вы используете List. Ваша версия лучше.
Here is the 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;
}
К сожалению, для этого решения также требуется .NET framework 3.5 или новее, поскольку HashSet не добавлялся до этой версии. Вы также можете использовать array.Distinct (), который является функцией LINQ.
Это, вероятно, не сохранит первоначальный порядок.
List<String> myStringList = new List<string>(); foreach (string s in myStringArray) { if (!myStringList.Contains(s)) { myStringList.Add(s); } }
Это О (п ^ 2), который не имеет значения для короткого списка, который будет объединен в комбо, но может быстро стать проблемой для большой коллекции.
Вот подход О (п * п), который использует пространство О (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';
}
}
Вышеупомянутые подходы хеш / linq - это то, что вы обычно используете в реальной жизни. Однако на собеседовании обычно ставят некоторые ограничения, например: постоянное пространство, которое исключает хэш или отсутствие внутреннего api - что исключает использование LINQ.
Как он может использовать пространство O (1), когда вам нужно хранить весь список? Начав с сортировки на месте, вы можете сделать O (nlogn) времени и O (n) памяти с гораздо меньшим количеством кода.
Что заставляет вас думать, что он хранит весь список? Это действительно работает на месте. И хотя это не условие в вопросе, мой код поддерживает порядок символов в исходной строке. Сортировка удалит это.
Внутренний цикл (strIn[j] == strIn[i]) будет сравнивать строку с самой собой, если это не учитывается с помощью оператора if.
Следующий фрагмент кода пытается удалить дубликаты из ArrayList, хотя это не оптимальное решение. Мне задали этот вопрос во время собеседования, чтобы удалить дубликаты с помощью рекурсии и без использования второго / временного arrayylist:
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);
}
}
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 ");
}
}
Может быть, 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 + ",");
}
Протестировано ниже, и оно работает. Что круто, так это то, что он также выполняет поиск с учетом культуры
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
- Это Вопрос на собеседовании спрашивают каждый раз. Теперь я его кодировал.
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) для этого вопроса.
Вы должны использовать сортировку слиянием
Этот код на 100% удаляет повторяющиеся значения из массива [как я использовал [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--;
}
}
}
Простое решение:
using System.Linq;
...
public static int[] Distinct(int[] handles)
{
return handles.ToList().Distinct().ToArray();
}
вы можете использовать этот код при работе с 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]);
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;
}
Ниже приведена простая логика в 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;
}
}
}
}
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;
}
объясните свой ответ, пожалуйста.
Универсальный метод расширения:
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;
}
}
}
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;
}
}
}
Это очень неэффективный способ сделать это. Посмотрите другие ответы, чтобы узнать, что они делают.
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, только код. в нем больше смысла, чем в тексте;)
Ответы, состоящие только из кода, являются ответами низкого качества. Добавьте объяснение, почему это работает.
Лучший путь? Трудно сказать, подход 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;
}
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. Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для читателей в будущем, и эти люди могут не знать причины вашего предложения кода.
К сожалению, этот код ничего не удаляет, поэтому не удаляет дубликаты.
Удаление дубликатов и игнорирование чувствительности к регистру с помощью 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
Найдите ответ ниже.
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;
}
}
Небольшой вклад, основанный на тесте, который я только что решил, может быть полезным и открытым для улучшения другими ведущими участниками здесь. Вот что я сделал:
В самом деле. Еще интереснее, когда массив уже отсортирован - в этом случае это можно сделать на месте за время O (n).