Pašalinti dublikatus iš <T> sąrašo, esančio C #

Ar kas nors turi greitą būdą, kaip paskirti bendrą „C #“ sąrašą?

417
06 сент. nustatė JC Grubbs 06 sept. 2008-09-06 22:15 '08 10:15 pm 2008-09-06 22:15
@ 24 atsakymai

Galbūt turėtumėte apsvarstyti galimybę naudoti „ HashSet“ .

Iš MSDN nuorodos:

 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(" }"); } }  
203
06 сент. Atsakykite Jason Bakerui rugsėjo 6 d 2008-09-06 22:21 '08, 10:21 val. 2008-09-06 22:21

Jei naudojate .Net 3+, galite naudoti Linq.

 List<T> withDupes = LoadSomeData(); List<T> noDupes = withDupes.Distinct().ToList(); 
708
06 сент. Atsakymą pateikė Factor Mystic 06 Sep. 2008-09-06 22:56 '08 at 10:56 pm 2008-09-06 22:56

Kaip apie: -

 var noDupes = list.Distinct().ToList(); 

.Net 3.5?

132
06 сент. atsakymas pateikiamas 06 sep . 2008-09-06 22:56 '08 at 10:56 pm 2008-09-06 22:56

Tiesiog inicijuokite „HashSet“ su tokio paties tipo sąrašu:

 var noDupes = new HashSet<T>(withDupes); 

Arba, jei norite grąžinti sąrašą:

 var noDupsList = new HashSet<T>(withDupes).ToList(); 
85
24 нояб. atsakymas pateikiamas net m . lapkričio 24 d. 2009-11-24 23:05 '09 11:05 val. 2009-11-24 23:05

Rūšiuoti, tada patikrinkite du ir du vienas šalia kito, nes dublikatai bus suspausti kartu.

Kažkas panašaus:

 list.Sort(); Int32 index = 0; while (index < list.Count - 1) { if (list[index] == list[index + 1]) list.RemoveAt(index); else index++; } 
45
06 сент. Atsakymas, kurį pateikė Lasse Vågsæther Karlsen 2008-09-06 22:20 '08 10:20 val. 2008-09-06 22:20

Jis dirbo man. tiesiog naudokite

 List<Type> liIDs = liIDs.Distinct().ToList<Type>(); 

Pakeiskite „Tipas“, pavyzdžiui, norimu tipu. vidinis

30
15 нояб. atsakymą pateikė Hossein Sarshar lapkričio 15 d. 2012-11-15 21:51 '12 at 9:51 PM 2012-11-15 21:51

Man patinka naudoti šią komandą:

 List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId) .GroupBy(s => s.City) .Select(grp => grp.FirstOrDefault()) .OrderBy(s => s.City) .ToList(); 

Turiu šiuos laukus savo sąraše: Id, StoreName, City, PostalCode Aš norėjau rodyti miestų sąrašą išskleidžiamajame sąraše, kuriame yra dvigubos vertės. Sprendimas: grupuokite pagal miestą ir pasirinkite pirmąjį sąrašą.

Tikiuosi, kad tai padės :)

23
27 июля '12 в 21:57 2012-07-27 21:57 atsakymą pateikė Eric , liepos 27 d. 12, 21:57 2012-07-27 21:57

Kaip sakė kronok .Net 3.5, galite naudoti „ Distinct() .

.Net 2 galite imituoti:

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

Tai gali būti panaudota bet kokiai surinkimo ir grąžinimo vertei išskaičiuoti iš pradinio užsakymo.

Paprastai daug greičiau filtruoti kolekciją (taip pat ir „ Distinct() , ir šį pavyzdį), nei pašalinti elementus iš jo.

22
07 сент. Atsakymas, kurį pateikė Keith 07 Sep 2008-09-07 12:44 '08, 12:44 2008-09-07 12:44

Plėtros metodas gali būti tinkamas būdas ... kažką panašaus į:

 public static List<T> Deduplicate<T>(this List<T> listToDeduplicate) { return listToDeduplicate.Distinct().ToList(); } 

Ir tada skambinkite, pavyzdžiui:

 List<int> myFilteredList = unfilteredList.Deduplicate(); 
12
03 апр. atsakymą pateikė Geoff Taylor 03 Bal. 2010-04-03 16:05 '10, 16:05 PM 2010-04-03 16:05

„Java“ (manau, kad C # yra daugiau ar mažiau identiškas):

 list = new ArrayList<T>(new HashSet<T>(list)) 

Jei tikrai norite pakeisti šaltinių sąrašą:

 List<T> noDupes = new ArrayList<T>(new HashSet<T>(list)); list.clear(); list.addAll(noDupes); 

Norėdami išlaikyti tvarką, tiesiog pakeiskite „HashSet“ su „LinkedHashSet“.

10
06 сент. Atsakyti Tom Hawtin - tackline 06 Sep 2008-09-06 22:29 '08 at 10:29 pm 2008-09-06 22:29

Naudokite „Linq Union“ metodą.

Pastaba Šis sprendimas nereikalauja žinių apie „Linq“, išskyrus tai, kad jis egzistuoja.

Kodas

Pradėkite pridėdami toliau savo klasės failo viršuje:

 using System.Linq; 

Dabar galite naudoti šiuos veiksmus norėdami pašalinti dublikatus iš objekto, pavadinto obj1 :

 obj1 = obj1.Union(obj1).ToList(); 

Pastaba Pervardykite obj1 į savo objekto pavadinimą.

Kaip tai veikia

  1. Sąjungos komanda nurodo vieną iš dviejų dviejų šaltinių objektų įrašų. Kadangi obj1 yra abu šaltinio objektai, jis sumažina obj1 į vieną iš kiekvieno įrašo.

  2. ToList() grąžina naują sąrašą. Tai yra būtina, nes „Linq“ komandos, pvz., „ Union grąžina rezultatą kaip skaičiuojamą rezultatą, o ne pakeitus pradinį sąrašą arba grąžindamos naują sąrašą.

6
13 февр. Knickerless-Noggins atsakymas yra vasario 13 d 2018-02-13 15:56 '18, 15:56 2018-02-13 15:56

Jei jums nereikia užsakymo, galite tiesiog nuvilkti elementus į „ HashSet , jei norite išsaugoti užsakymą, galite tai padaryti:

 var unique = new List<T>(); var hs = new HashSet<T>(); foreach (T t in list) if (hs.Add(t)) unique.Add(t); 

Arba „Linq“ kelias:

 var hs = new HashSet<T>(); list.All( x => hs.Add(x) ); 

Redagavimas:HashSet metodas yra O(N) laikas ir O(N) erdvė rūšiavimo metu, o tada sukuriant unikalų (kaip siūlė @ lassevk ir tt) yra O(N*lgN) laikas ir O(1) erdvė, todėl man neaišku (kaip buvo iš pirmo žvilgsnio), kad rūšiavimo metodas yra prastesnis (atsiprašau už laikiną balsų sumažėjimą ...)

5
06 сент. Atsakymą pateikė Motti 06 Sep. 2008-09-06 22:32 '08 at 10:32 2008-09-06 22:32

Čia naudojamas išplėtimo metodas kaimyniniams dublikatams pašalinti in situ. Pirmiausia skambinkite Rūšiuoti () ir eikite į tą patį IComparer. Tai turėtų būti veiksmingesnė nei Lasse V. Karlsen versija, kuri pakartotinai ragina „RemoveAt“ (kuris veda prie kelių blokų judėjimo).

 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); } 
5
25 февр. atsakymą gary pateikė vasario 25 d. 2011-02-25 09:15 '11 at 9:15 am 2011-02-25 09:15

Kaip pagalbinis metodas (be Linq):

 public static List<T> Distinct<T>(this List<T> list) { return (new HashSet<T>(list)).ToList(); } 
5
19 нояб. Atsakymas duotas Grant 19 lapkričio. 2014-11-19 00:45 '14 - 0:45 2014-11-19 00:45

Gali būti lengviau tik įsitikinti, kad dublikatai nėra įtraukti į sąrašą.

 if(items.IndexOf(new_item) < 0) items.add(new_item) 
3
29 июня '12 в 5:33 2012-06-29 05:33 Atsakymą pateikė Chris , birželio 29 d., 12 val., 5:33 2012-06-29 05:33

Galite naudoti „Union“

 obj2 = obj1.Union(obj1).ToList(); 
1
06 авг. atsakymas duotas flagamba 06 rug . 2017-08-06 18:16 '17, 18:16 pm 2017-08-06 18:16

Paprastas intuityvus įgyvendinimas:

 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; } 
1
19 апр. Moctar Haiz atsakymas 19 d 2018-04-19 12:05 '18, 12:05 val. 2018-04-19 12:05

ĮdiegęMoreLINQ“ paketą per „Nuget“, galite lengvai atskirti objektų sąrašą pagal turtą

 IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 
1
15 марта '17 в 17:51 2017-03-15 17:51 atsakymą pateikė dush88c kovo 15 d. 17, 17:51 2017-03-15 17:51

David J .. Atsakymas yra geras būdas, nereikia papildomų objektų, rūšiavimo ir kt. Tačiau tai gali būti patobulinta:

for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)

Taigi, išorinis kontūras eina į viršų žemyn visam sąrašui, tačiau vidinė kilpa eina žemiau ", kol pasiekiamas išorinio kontūro padėtis."

Išorinė kilpa užtikrina, kad visas sąrašas yra apdorojamas, vidinė kilpa suranda faktinius dublikatus, tai gali įvykti tik toje dalyje, kurioje išorinė kilpa dar nėra apdorota.

Arba, jei nenorite atlikti „iš apačios į viršų“ vidinės linijos, galite pradėti vidinę kilpą naudodami „ExternalIndex + 1“.

1
22 окт. Spalio 22 d. Svečio atsakymas . 2013-10-22 14:10 '13, 14:10 pm 2013-10-22 14:10

Yra daug būdų išspręsti problemą - dublikatai sąraše, žemiau - vienas iš jų:

 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 ur making a search if(!containerList.Contains(duplicateContainer) //Add object when not found in the new class object { filteredList.Add(container); } } 

Sveikinimai Ravi Ganesyan

1
10 апр. atsakymas, kurį pateikė Ravi Ganesan 10 Bal 2011-04-10 08:02 '11 at 8:02 2011-04-10 08:02

Kitas būdas .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(); } 
1
10 февр. Atsakymas pateiktas Bhasin 10 vasario mėn. 2011-02-10 09:55 '11 at 9:55 2011-02-10 09:55
  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++; } } } 
1
14 мая '14 в 14:11 2014-05-14 14:11 atsakymą pateikė Paulius Richardsas gegužės 14 d. 14 val. 14:11 2014-05-14 14:11

Čia yra paprastas sprendimas, kuriam nereikia jokio sunkiai perskaitymo LINQ arba bet kokio sąrašo išankstinio rūšiavimo.

  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 } } } } 
1
14 февр. Atsakymas David J. Feb. 14. 2012-02-14 15:20 '12, 15:20 pm 2012-02-14 15:20

Jei turite „ Product ir „ Customer “ klasę ir norime iš jų sąrašo pašalinti pasikartojančius elementus

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

Turite apibrėžti bendrąją klasę žemiau esančioje formoje.

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

tada sąraše galite pašalinti pasikartojančius elementus.

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

Šis kodas pašalina dvigubus elementus pagal Id Jei norite pašalinti pasikartojančius elementus su kita nuosavybe, galite pakeisti nameof(YourClass.DuplicateProperty) su tuo pačiu nameof(Customer.CustomerName) tada ištrinti pasikartojančius elementus nameof(Customer.CustomerName) CustomerName .

0
02 дек. Reza Jenabi atsakymas 02.12 2018-12-02 14:07 '18, 14:07, 2018-12-02 14:07

Žr. Kitus klausimus apie žymes arba užduoti klausimą