Condition: dans une liste non triée, déterminez s'il existe un doublon. La façon typique de procéder est une boucle imbriquée n-carré. Je me demande comment les autres résolvent cela. Existe-t-il une méthode élégante et performante dans Linq? Quelque chose de générique qui prend un lambda ou un comparateur serait bien.
Sauf si je manque quelque chose, alors vous devriez pouvoir vous en sortir avec quelque chose de simple en utilisant Distinct()
. Certes, ce ne sera pas l'implémentation la plus complexe que vous pourriez trouver, mais elle vous dira si des doublons sont supprimés:
var list = new List<string>();
// Fill the list
if(list.Count != list.Distinct().Count())
{
// Duplicates exist
}
Selon l'article d'Eric White sur la façon de Trouver des doublons à l'aide de LINQ :
Un moyen simple de rechercher des doublons consiste à écrire une requête qui regroupe par identifiant, puis à filtrer les groupes qui ont plusieurs membres. Dans l'exemple suivant, nous voulons savoir que 4 et 3 sont des doublons:
int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 }; var duplicates = listOfItems .GroupBy(i => i) .Where(g => g.Count() > 1) .Select(g => g.Key); foreach (var d in duplicates) Console.WriteLine(d); // 4,3
Afin de permettre un court-circuit si le doublon existe au début de la liste, vous pouvez ajouter un HashSet<T>
et vérifiez la valeur de retour de son .Add
méthode.
En utilisant .Any
vous pouvez court-circuiter l'énumération dès que vous en trouvez un doublon.
Voici une méthode d'extension LINQ en C # et VB:
public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable)
{
var knownKeys = new HashSet<T>();
return enumerable.Any(item => !knownKeys.Add(item));
}
<Extension>
Public Function ContainsDuplicates(Of T)(ByVal enumerable As IEnumerable(Of T)) As Boolean
Dim knownKeys As New HashSet(Of T)
Return enumerable.Any(Function(item) Not knownKeys.Add(item))
End Function
Remarque : pour vérifier s'il y a non doublons, changez simplement Any
en All
Placez tous les éléments dans un ensemble et si le nombre de l'ensemble est différent du nombre de la liste, il y a un doublon.
bool hasDuplicates<T>(List<T> myList) {
var hs = new HashSet<T>();
for (var i = 0; i < myList.Count; ++i) {
if (!hs.Add(myList[i])) return true;
}
return false;
}
Devrait être plus efficace que Distinct car il n'est pas nécessaire de parcourir toute la liste.
Vous pouvez utiliser la méthode IEnumerable.GroupBy.
var list = new List<string> {"1", "2","3", "1", "2"};
var hasDuplicates = list.GroupBy(x => x).Any(x => x.Skip(1).Any());
Quelque chose dans ce sens est relativement simple et vous fournira un nombre de doublons.
var something = new List<string>() { "One", "One", "Two", "Three" };
var dictionary = new Dictionary<string, int>();
something.ForEach(s =>
{
if (dictionary.ContainsKey(s))
{
dictionary[s]++;
}
else
{
dictionary[s] = 1;
}
});
J'imagine que cela est similaire à la mise en œuvre de Distinct, bien que je ne sois pas certain.
Si vous utilisez des entiers ou des ensembles bien ordonnés, utilisez un arbre binaire pour les performances O (nlog n).
Alternativement, trouvez un autre moyen de tri plus rapide, puis vérifiez simplement que chaque valeur est différente de la précédente.
Vous pouvez utiliser la méthode d'extension Distinct () pour IEnumerable
Utilisation Enumerable.Any
avec HashSet.Add
comme:
List<string> list = new List<string> {"A", "A", "B", "C", "D"};
HashSet<string> hashSet = new HashSet<string>();
if(list.Any(r => !hashSet.Add(r)))
{
//duplicate exists.
}
HashSet.Add
renverrait false
si l'élément existe déjà dans le HashSet
. Cela ne répétera pas toute la liste.
Vous pouvez utiliser l'instruction Distinct()
pour rechercher des enregistrements uniques. Comparez ensuite avec la liste générique d'origine comme celle-ci:
if (dgCoil.ItemsSource.Cast<BLL.Coil>().ToList().Count != dgCoil.ItemsSource.Cast<BLL.Coil>().Select(c => c.CoilNo).Distinct().Count())
{
//Duplicate detected !!
return;
}