Удалить дубликаты из списка <T> в C #
496517 просмотра
25 ответа
У кого-нибудь есть быстрый способ дедупликации универсального списка в C #?
Автор: JC Grubbs Источник Размещён: 17.05.2019 02:46Ответы (25)
206 плюса
Возможно, вам следует рассмотреть возможность использования HashSet .
Из ссылки MSDN:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
HashSet<int> evenNumbers = new HashSet<int>();
HashSet<int> oddNumbers = new HashSet<int>();
for (int i = 0; i < 5; i++)
{
// Populate numbers with just even numbers.
evenNumbers.Add(i * 2);
// Populate oddNumbers with just odd numbers.
oddNumbers.Add((i * 2) + 1);
}
Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
DisplaySet(evenNumbers);
Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
DisplaySet(oddNumbers);
// Create a new HashSet populated with even numbers.
HashSet<int> numbers = new HashSet<int>(evenNumbers);
Console.WriteLine("numbers UnionWith oddNumbers...");
numbers.UnionWith(oddNumbers);
Console.Write("numbers contains {0} elements: ", numbers.Count);
DisplaySet(numbers);
}
private static void DisplaySet(HashSet<int> set)
{
Console.Write("{");
foreach (int i in set)
{
Console.Write(" {0}", i);
}
Console.WriteLine(" }");
}
}
/* This example produces output similar to the following:
* evenNumbers contains 5 elements: { 0 2 4 6 8 }
* oddNumbers contains 5 elements: { 1 3 5 7 9 }
* numbers UnionWith oddNumbers...
* numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }
*/
Автор: Jason Baker
Размещён: 06.09.2008 07:21
729 плюса
Если вы используете .Net 3+, вы можете использовать Linq.
List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();
Автор: Factor Mystic
Размещён: 06.09.2008 07:56
137 плюса
Как насчет:-
var noDupes = list.Distinct().ToList();
В .net 3.5?
Автор: ljs Размещён: 06.09.2008 07:5685 плюса
Просто инициализируйте HashSet списком того же типа:
var noDupes = new HashSet<T>(withDupes);
Или, если вы хотите вернуть список:
var noDupsList = new HashSet<T>(withDupes).ToList();
Автор: Even Mien
Размещён: 24.11.2009 08:05
45 плюса
Сортируйте его, затем отметьте два и два рядом друг с другом, так как дубликаты будут объединяться.
Что-то вроде этого:
list.Sort();
Int32 index = 0;
while (index < list.Count - 1)
{
if (list[index] == list[index + 1])
list.RemoveAt(index);
else
index++;
}
Автор: Lasse Vågsæther Karlsen
Размещён: 06.09.2008 07:20
30 плюса
Это сработало для меня. просто используйте
List<Type> liIDs = liIDs.Distinct().ToList<Type>();
Замените «Тип» на желаемый тип, например, int.
Автор: Hossein Sarshar Размещён: 15.11.2012 06:5126 плюса
Мне нравится использовать эту команду:
List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId)
.GroupBy(s => s.City)
.Select(grp => grp.FirstOrDefault())
.OrderBy(s => s.City)
.ToList();
У меня есть эти поля в моем списке: Id, StoreName, City, PostalCode Я хотел показать список городов в выпадающем списке, который имеет повторяющиеся значения. Решение: сгруппируйте по городам, затем выберите первый в списке.
Я надеюсь, что это помогает :)
Автор: Eric Размещён: 27.07.2012 06:5722 плюса
Как сказал кроноз в .Net 3.5 вы можете использовать Distinct()
.
В .Net 2 вы можете имитировать это:
public IEnumerable<T> DedupCollection<T> (IEnumerable<T> input)
{
var passedValues = new HashSet<T>();
// Relatively simple dupe check alg used as example
foreach(T item in input)
if(passedValues.Add(item)) // True if item is new
yield return item;
}
Это может быть использовано для дедупликации любой коллекции и будет возвращать значения в исходном порядке.
Обычно фильтровать коллекцию гораздо быстрее (как Distinct()
и в этом примере), чем удалять из нее элементы.
12 плюса
Метод расширения может быть приличным способом ... что-то вроде этого:
public static List<T> Deduplicate<T>(this List<T> listToDeduplicate)
{
return listToDeduplicate.Distinct().ToList();
}
А потом позвоните вот так, например:
List<int> myFilteredList = unfilteredList.Deduplicate();
Автор: Geoff Taylor
Размещён: 03.04.2010 01:05
10 плюса
В Java (я предполагаю, что C # более или менее идентичен):
list = new ArrayList<T>(new HashSet<T>(list))
Если вы действительно хотите изменить исходный список:
List<T> noDupes = new ArrayList<T>(new HashSet<T>(list));
list.clear();
list.addAll(noDupes);
Чтобы сохранить порядок, просто замените HashSet на LinkedHashSet.
Автор: Tom Hawtin - tackline Размещён: 06.09.2008 07:296 плюса
Используйте метод Linq's Union .
Примечание. Это решение не требует никаких знаний о Linq, кроме того, что оно существует.
Код
Начните с добавления следующего в начало вашего файла классов:
using System.Linq;
Теперь вы можете использовать следующее для удаления дубликатов из объекта с именем obj1
:
obj1 = obj1.Union(obj1).ToList();
Примечание: переименуйте obj1
в название вашего объекта.
Как это устроено
Команда Union перечисляет одну из каждой записи двух исходных объектов. Поскольку obj1 - оба исходных объекта, это сводит obj1 к одной из каждой записи.
В
ToList()
возвращает новый список. Это необходимо, потому что команды Linq likeUnion
возвращают результат как результат IEnumerable вместо изменения исходного списка или возврата нового списка.
5 плюса
Если вы не заботитесь о порядке вы можете просто засунуть элементы в HashSet
, если вы действительно хотите сохранить заказ вы можете сделать что - то вроде этого:
var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
if (hs.Add(t))
unique.Add(t);
Или Линк путь:
var hs = new HashSet<T>();
list.All( x => hs.Add(x) );
Edit:HashSet
метод O(N)
времени и O(N)
пространства во время сортировки , а затем сделать уникальный (как это было предложено @ lassevk и других) есть O(N*lgN)
время и O(1)
пространство , так что это не так ясно для меня (как это было на первый взгляд) , что сортировка путь уступает (мой извиняюсь за временное отрицательное голосование ...)
5 плюса
Вот метод расширения для удаления соседних дубликатов на месте. Сначала вызовите Sort () и передайте в тот же IComparer. Это должно быть более эффективно, чем версия Лассе В. Карлсена, в которой неоднократно вызывается RemoveAt (что приводит к перемещению памяти из нескольких блоков).
public static void RemoveAdjacentDuplicates<T>(this List<T> List, IComparer<T> Comparer)
{
int NumUnique = 0;
for (int i = 0; i < List.Count; i++)
if ((i == 0) || (Comparer.Compare(List[NumUnique - 1], List[i]) != 0))
List[NumUnique++] = List[i];
List.RemoveRange(NumUnique, List.Count - NumUnique);
}
Автор: gary
Размещён: 25.02.2011 06:15
5 плюса
В качестве вспомогательного метода (без Linq):
public static List<T> Distinct<T>(this List<T> list)
{
return (new HashSet<T>(list)).ToList();
}
Автор: Grant
Размещён: 18.11.2014 09:45
3 плюса
Может быть проще просто убедиться, что дубликаты не добавляются в список.
if(items.IndexOf(new_item) < 0)
items.add(new_item)
Автор: Chris
Размещён: 29.06.2012 02:33
3 плюса
Установив пакет MoreLINQ через Nuget, вы можете легко различать список объектов по свойству
IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode);
Автор: dush88c
Размещён: 15.03.2017 02:51
1 плюс
Еще один способ в .Net 2.0
static void Main(string[] args)
{
List<string> alpha = new List<string>();
for(char a = 'a'; a <= 'd'; a++)
{
alpha.Add(a.ToString());
alpha.Add(a.ToString());
}
Console.WriteLine("Data :");
alpha.ForEach(delegate(string t) { Console.WriteLine(t); });
alpha.ForEach(delegate (string v)
{
if (alpha.FindAll(delegate(string t) { return t == v; }).Count > 1)
alpha.Remove(v);
});
Console.WriteLine("Unique Result :");
alpha.ForEach(delegate(string t) { Console.WriteLine(t);});
Console.ReadKey();
}
Автор: Bhasin
Размещён: 10.02.2011 06:55
1 плюс
Есть много способов решить - проблема с дубликатами в списке, ниже один из них:
List<Container> containerList = LoadContainer();//Assume it has duplicates
List<Container> filteredList = new List<Container>();
foreach (var container in containerList)
{
Container duplicateContainer = containerList.Find(delegate(Container checkContainer)
{ return (checkContainer.UniqueId == container.UniqueId); });
//Assume 'UniqueId' is the property of the Container class on which u r making a search
if(!containerList.Contains(duplicateContainer) //Add object when not found in the new class object
{
filteredList.Add(container);
}
}
Ура Рави Ганесан
Автор: Ravi Ganesan Размещён: 10.04.2011 05:021 плюс
Вот простое решение, которое не требует трудно читаемого LINQ или какой-либо предварительной сортировки списка.
private static void CheckForDuplicateItems(List<string> items)
{
if (items == null ||
items.Count == 0)
return;
for (int outerIndex = 0; outerIndex < items.Count; outerIndex++)
{
for (int innerIndex = 0; innerIndex < items.Count; innerIndex++)
{
if (innerIndex == outerIndex) continue;
if (items[outerIndex].Equals(items[innerIndex]))
{
// Duplicate Found
}
}
}
}
Автор: David J.
Размещён: 14.02.2012 12:20
1 плюс
Ответ Дэвида Дж. - хороший метод, не требующий дополнительных объектов, сортировки и т. Д. Однако его можно улучшить:
for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)
Таким образом, внешний цикл идет сверху вниз для всего списка, но внутренний цикл идет снизу «до тех пор, пока не будет достигнута позиция внешнего цикла».
Внешний цикл гарантирует, что весь список обработан, внутренний цикл находит фактические дубликаты, они могут происходить только в той части, которую внешний цикл еще не обработал.
Или, если вы не хотите делать восходящий цикл для внутреннего цикла, вы можете запустить внутренний цикл в externalIndex + 1.
Автор: Guest Размещён: 22.10.2013 11:101 плюс
public static void RemoveDuplicates<T>(IList<T> list )
{
if (list == null)
{
return;
}
int i = 1;
while(i<list.Count)
{
int j = 0;
bool remove = false;
while (j < i && !remove)
{
if (list[i].Equals(list[j]))
{
remove = true;
}
j++;
}
if (remove)
{
list.RemoveAt(i);
}
else
{
i++;
}
}
}
Автор: Paul Richards
Размещён: 14.05.2014 11:11
1 плюс
Вы можете использовать Союз
obj2 = obj1.Union(obj1).ToList();
Автор: flagamba
Размещён: 06.08.2017 03:16
1 плюс
Простая интуитивно понятная реализация:
public static List<PointF> RemoveDuplicates(List<PointF> listPoints)
{
List<PointF> result = new List<PointF>();
for (int i = 0; i < listPoints.Count; i++)
{
if (!result.Contains(listPoints[i]))
result.Add(listPoints[i]);
}
return result;
}
Автор: Moctar Haiz
Размещён: 19.04.2018 09:05
1 плюс
Если у вас есть классы буксирных Product
и Customer
мы хотим , чтобы удалить повторяющиеся элементы из своего списка
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; }
}
Вы должны определить общий класс в форме ниже
public class ItemEqualityComparer<T> : IEqualityComparer<T> where T : class
{
private readonly PropertyInfo _propertyInfo;
public ItemEqualityComparer(string keyItem)
{
_propertyInfo = typeof(T).GetProperty(keyItem, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
}
public bool Equals(T x, T y)
{
var xValue = _propertyInfo?.GetValue(x, null);
var yValue = _propertyInfo?.GetValue(y, null);
return xValue != null && yValue != null && xValue.Equals(yValue);
}
public int GetHashCode(T obj)
{
var propertyValue = _propertyInfo.GetValue(obj, null);
return propertyValue == null ? 0 : propertyValue.GetHashCode();
}
}
Затем вы можете удалить дубликаты в вашем списке.
var products = new List<Product>
{
new Product{ProductName = "product 1" ,Id = 1,},
new Product{ProductName = "product 2" ,Id = 2,},
new Product{ProductName = "product 2" ,Id = 4,},
new Product{ProductName = "product 2" ,Id = 4,},
};
var productList = products.Distinct(new ItemEqualityComparer<Product>(nameof(Product.Id))).ToList();
var customers = new List<Customer>
{
new Customer{CustomerName = "Customer 1" ,Id = 5,},
new Customer{CustomerName = "Customer 2" ,Id = 5,},
new Customer{CustomerName = "Customer 2" ,Id = 5,},
new Customer{CustomerName = "Customer 2" ,Id = 5,},
};
var customerList = customers.Distinct(new ItemEqualityComparer<Customer>(nameof(Customer.Id))).ToList();
этот код удаление дубликатов детали , Id
если вы хотите удалить повторяющиеся элементы от другого имущества, вы можете изменить то nameof(YourClass.DuplicateProperty)
же nameof(Customer.CustomerName)
затем удалить повторяющиеся элементы по CustomerName
недвижимости.
0 плюса
Это берет различные элементы без дублирования элементов и снова преобразует их в список.
List myNoneDuplicateValue = listValueWithDuplicate.Distinct (). ToList ();
Автор: Alfred Udah Размещён: 13.03.2019 10:58Вопросы из категории :
- c# Преобразовать десятичную в двойную?
- c# Как рассчитать чей-то возраст в C #?
- c# Как вы сортируете словарь по значению?
- c# В чем разница между int и Integer в Java и C #?
- c# Как создать новый экземпляр объекта из Типа
- list Функция транспонирования / распаковки (обратная сторона zip)?
- list How would you make a comma-separated string from a list of strings?
- list Удалить дубликаты из списка <T> в C #
- list Console.WriteLine и общий список
- list Как проверить, если список пуст?
- generics Почему в C # нельзя хранить объект List <string> в переменной List <object>
- generics Преобразование общего типа из строки
- generics Лучший способ проверить, является ли универсальный тип строкой? (С #)
- generics Есть ли ограничение, которое ограничивает мой общий метод численными типами?
- generics Каковы различия между «универсальными» типами в C ++ и Java?
- duplicates Как удалить дубликаты из массива C #?
- duplicates Как я могу удалить дубликаты строк?
- duplicates Как удалить повторяющиеся элементы из ArrayList?
- duplicates Дублирование экземпляров модели и связанных с ними объектов в Django / Algorithm для повторного дублирования объекта