Supprimer les doublons d'une liste en C#
23 réponses
peut-être devriez-vous envisager d'utiliser un HashSet .
De la MSDN lien:
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 }
*/
si vous utilisez .Net 3+, Vous pouvez utiliser Linq.
List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();
que dire de: -
var noDupes = list.Distinct().ToList();
dans .net 3.5?
il suffit D'initialiser un HashSet avec une liste du même type:
var noDupes = new HashSet<T>(withDupes);
ou, si vous voulez une liste retournée:
var noDupsList = new HashSet<T>(withDupes).ToList();
Triez-le, puis cochez deux et deux à côté de l'autre, car les doublons vont s'agglutiner.
quelque chose comme ça:
list.Sort();
Int32 index = 0;
while (index < list.Count - 1)
{
if (list[index] == list[index + 1])
list.RemoveAt(index);
else
index++;
}
ça a marché pour moi. il suffit d'utiliser
List<Type> liIDs = liIDs.Distinct().ToList<Type>();
remplacer" Type " par le type désiré, par exemple int.
j'aime utiliser cette commande:
List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId)
.GroupBy(s => s.City)
.Select(grp => grp.FirstOrDefault())
.OrderBy(s => s.City)
.ToList();
j'ai ces champs dans ma liste: Id, StoreName, City, PostalCode Je voulais montrer la liste des villes dans une liste déroulante qui a des valeurs dupliquées. solution: Groupe par ville puis choisissez le premier de la liste.
j'espère que cela aide :)
comme kronoz l'a dit dans .Net 3.5, vous pouvez utiliser Distinct()
.
dans .Net 2 Vous pouvez l'imiter:
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;
}
cela peut être utilisé pour dépouiller n'importe quelle collection et retourner les valeurs dans l'ordre original.
normalement, il est beaucoup plus rapide de filtrer une collection (comme Distinct()
et cet échantillon le fait) qu'il ne le serait pour en retirer des articles.
une méthode d'extension pourrait être une bonne façon de faire... quelque chose comme ceci:
public static List<T> Deduplicate<T>(this List<T> listToDeduplicate)
{
return listToDeduplicate.Distinct().ToList();
}
et puis appelez comme ceci, par exemple:
List<int> myFilteredList = unfilteredList.Deduplicate();
en Java (je suppose que C# est plus ou moins identique):
list = new ArrayList<T>(new HashSet<T>(list))
si vous avez vraiment voulu muter la liste originale:
List<T> noDupes = new ArrayList<T>(new HashSet<T>(list));
list.clear();
list.addAll(noDupes);
pour préserver l'ordre, il suffit de remplacer le HashSet par LinkedHashSet.
si vous ne vous souciez pas de la commande, vous pouvez simplement mettre les articles dans un HashSet
, si vous do si vous voulez maintenir la commande, vous pouvez faire quelque chose comme ceci:
var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
if (hs.Add(t))
unique.Add(t);
Ou Linq:
var hs = new HashSet<T>();
list.All( x => hs.Add(x) );
Edit: la méthode HashSet
est O(N)
time et O(N)
space tout en triant et en faisant unique (comme suggéré par @ lassevk et autres) est O(N*lgN)
temps et O(1)
espace de sorte qu'il n'est pas si clair pour moi (comme il l'était à première vue) que la voie de tri est inférieure (mes excuses pour le vote temporaire vers le bas...)
comme méthode d'aide (sans Linq):
public static List<T> Distinct<T>(this List<T> list)
{
return (new HashSet<T>(list)).ToList();
}
utiliser la méthode de Linq Union .
Note: Cette solution n'exige aucune connaissance de Linq, sauf qu'elle existe.
Code
commencez par ajouter ce qui suit Au début de votre fichier de classe:
using System.Linq;
Maintenant, vous pouvez utiliser ce qui suit pour supprimer les doublons d'un objet appelé, obj1
:
obj1 = obj1.Union(obj1).ToList();
Note: renommez obj1
au nom de votre objet.
Comment ça marche
-
la commande Union Liste une entrée de chaque objet source. Comme obj1 est à la fois un objet source, cela réduit obj1 à une entrée par entrée.
-
le
ToList()
retourne une nouvelle liste. Cela est nécessaire, parce que les commandes de Linq commeUnion
retourne le résultat comme un résultat IEnumerable au lieu de modifier la liste originale ou de retourner une nouvelle liste.
Voici une méthode d'extension pour enlever les doublons adjacents in-situ. Appeler D'abord Sort() et passer dans le même IComparer. Cela devrait être plus efficace que la version de Lasse V. Karlsen qui appelle RemoveAt à plusieurs reprises (résultant en plusieurs blocks de déplacement de mémoire).
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);
}
pourrait être plus facile de simplement s'assurer que les doublons ne sont pas ajoutés à la liste.
if(items.IndexOf(new_item) < 0)
items.add(new_item)
d'une Autre manière .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();
}
il y a plusieurs façons de résoudre - la question des doublons dans la liste, ci-dessous est l'une d'entre elles:
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);
}
}
santé Ravi Ganesan
Voici une solution simple qui ne nécessite pas de LINQ difficile à lire ou de tri préalable de la liste.
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
}
}
}
}
la réponse de David J. est une bonne méthode, pas besoin d'objets supplémentaires, de tri, etc. Il peut toutefois être amélioré sur:
for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)
ainsi la boucle extérieure descend en haut pour la liste entière, mais la boucle intérieure descend en bas "jusqu'à ce que la position de la boucle extérieure soit atteinte".
la boucle extérieure s'assure que la liste entière est traitée, la boucle intérieure trouve les doublons réels, ceux-ci ne peuvent se produire que dans la partie que l'extérieur la boucle n'a pas encore été traités.
ou si vous ne voulez pas faire bottom up pour la boucle intérieure, vous pouvez faire démarrer la boucle intérieure à outerIndex + 1.
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++;
}
}
}
une simple implémentation intuitive:
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;
}