2016-09-07 1 views
0

Quels éléments seront supprimés de la liste résultante lorsque DISTINCT.ToList() est appliqué dans l'illustration suivante? La première entrée (c'est-à-dire qui a été ajoutée en premier à la liste) parmi les doublons est-elle conservée dans la nouvelle liste renvoyée? Sinon, existe-t-il un moyen de rendre le DISTINCT.ToList() pour conserver la première entrée parmi les doublons de la nouvelle liste renvoyée?L'ordre de renvoi des éléments dans la liste résultante lors de l'utilisation de List.Distinct()

Dim values As List(Of Integer) = New List(Of Integer) 
    values.Add(1) 
    values.Add(5) 
    values.Add(2) 
    values.Add(3) 
    values.Add(2) 
    values.Add(3) 
    values.Add(4) 
    values.Add(2) 
    values.Add(2) 
    values.Add(3) 
    values.Add(3) 
    values.Add(3) 

    Dim items As List(Of Integer) = values.Distinct().ToList 

    ' Display result. 
    For Each i As Integer In items 
     Console.WriteLine(i) 
    Next 

Expected output: 
1 
5 
2 
3 
4 

Cette MSDN dit la page "Le Distinct (Of TSource) (IEnumerable (Of TSource)) renvoie une séquence non ordonnée qui ne contient pas les valeurs en double". Y a-t-il un moyen de contourner ceci?

+2

En fait, aucun élément ne sera supprimé de la liste, une nouvelle liste contenant des éléments distincts est retournée. – hellowstone

+1

Vous pouvez toujours ajouter vous-même une méthode d'extension qui l'ordonne: 'public static IOrderedEnumerable OrderedDistinct (cette donnée IEnumerable ) {return data.Distinct(). OrderBy (x => x); } ' – Maarten

+0

La liste retournée avec l'opération' Distinct' ne contient que les premiers éléments originaux et il n'y a pas d'ordre. Vous devez donc vous attendre à la sortie attendue dans votre exemple. – hellowstone

Répondre

4

Non, vous ne pouvez pas utiliser Distinct pour contourner cela. En l'occurrence, cela fonctionne exactement comme prévu, mais la documentation indique explicitement qu'elle n'est pas garantie. Par conséquent, la mise en œuvre peut changer dans les futures versions du framework de sorte que vous ne pouvez pas compter dessus. La méthode est triviale à écrire. En fait, vous pouvez même copier the framework implementation.

Encore une fois - il fonctionne actuellement comme vous le souhaitez, mais il n'est pas garanti de le faire à l'avenir. D'autre part, je suis assez confiant que cette implémentation ne changera jamais car je ne peux pas imaginer qu'une implémentation plus efficace existe.

Voici une mise en œuvre pour être complet (désolé il est C# et non VB.NET)

public static class MyEnumerable 
{ 
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) 
    { 
     if (source == null) 
     { 
      throw new ArgumentNullException(nameof(source)); 
     } 

     var items = new HashSet<T>(); 

     foreach (T item in source) 
     { 
      if (items.Add(item)) 
      { 
       yield return item; 
      } 
     } 
    } 
} 
1

Non, vous ne pouvez pas contourner avec des méthodes standard fournies par le cadre. Vous pouvez le contourner en le codant vous-même comme suggéré par Stilgar. Avec votre exemple fourni en sélectionnant le premier élément par index est techniquement non pertinent car vous ne serez pas en mesure de savoir si c'était la première ou la centaine d'occurrences dans la liste depuis que la structure est Int.

Mais cela dit je suppose que vous utilisez un objet personnalisé. Dans ce cas, votre commande provient d'une sorte de tri. Dans ce cas je vous suggère plutôt d'utiliser un GroupBy<> puis pour chaque groupe de commander les articles par votre déclaration OrderBy<> et faire un First<> sur cela. Regrouper par et Distinct sont très proches.

distinct peut être remplacé par un groupe par et puis d'abord sur chaque groupe. En effet, c'est beaucoup plus lent que la mise en œuvre réelle, mais le but ici est d'expliquer comment vous pouvez utiliser cela pour personnaliser la sortie si vous avez besoin de plus que simplement le premier élément.