2016-06-20 14 views
1

ich eine Liste der Filme, und ich brauche sie mit einer anderen Liste zu verschmelzen und vervielfältigen.DistinctBy aber ignorieren null/leer

Ich bin mit Jon Skeet DistinctBy(m => m.SomeUniqueMovieProperty) dies zu erreichen, und es funktioniert OK. Außer, wir fanden bald heraus, dass es Fälle geben würde, in denen 10-20% der Filme (in jeder Liste) diese Eigenschaft nicht ausgefüllt haben, was DistinctBy dazu veranlasst, sie in einen glücklichen Film zu stürzen.

Dies ist ein Problem, wollen wir alle diese Filme halten, die für diese Eigenschaft keinen Wert haben. Anfangs dachte ich daran, diese Filme aus jeder Sammlung zu extrahieren, zu duplizieren und dann wieder zusammenzufügen, gibt es eine kürzere Lösung für dieses Problem?

+0

würde ich Ihrer Wahl folgen. Filtern Sie die Einsen aus, um den Wert der Eigenschaft null zu erhalten. Führen Sie distinct nach dem Wert aus, und führen Sie ihn dann mit den gefilterten Werten zusammen. – rageit

Antwort

3

verketten die Ergebnisse DistinctBy() mit den Ergebnissen der Where([null or empty]).

var nullMovies = allMovies.Where(m=>string.IsNullOrEmpty(m.SomeUniqueMovieProperty)); 

var distinctNonNullMovies = allMovies.Where(m => !string.IsNullOrEmpty(m.SomeUniqueMovieProperty)).DistinctBy(m => m.SomeUniqueMovieProperty); 

var result = nullMovies.Concat(distinctNonNullMovies); 
+0

Wir können leere Werte für diese Eigenschaft haben, also würde diese Lösung den Kuchen nehmen. Scotts Lösung kann gemacht werden, damit zu arbeiten? aber wird weniger lesbar.+1 zu seiner Lösung könnte auch in einem anderen Fall funktionieren – FailedUnitTest

+1

Der einzige Nachteil dieser Lösung ist, dass es mehrere Aufzählungen von 'allMovies' verursacht –

3

Wenn Sie all die Nullen einschließen möchten Sie die Null-Eigenschaft mit etwas ersetzen müssen, die einzigartig ist, wenn es null ist. Unter der Annahme, dass die Eigenschaft eine Zeichenfolge ist, wird Guid für diesen Job gut funktionieren.

.DistinctBy(m => m.SomeUniqueMovieProperty ?? Guid.NewGuid().ToString()) 

Jedes Mal, wenn es eine Eigenschaft mit einem Nullwert trifft, wird es mit einem zufälligen neuen GUID-Wert gefüllt.


Wenn Sie auch leer Titel nicht haben, um die Abfrage erhalten entfernt Änderung

.DistinctBy(m => String.IsNullOrEmpty(m.SomeUniqueMovieProperty) ? Guid.NewGuid().ToString() : m.SomeUniqueMovieProperty) 

Eine weitere Option ist Ihre eigene DistinctBy machen, die die Art und Weise Sie wollen verhält. Dies ist eine optimierte Version der original source, die nur den Filter anwendet, wenn shouldApplyFilter Wahr zurückgibt, Kommentare werden auch der Kürze halber entfernt.

static partial class MoreEnumerable 
{ 
    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter) 
    { 
     return source.ConditionalDistinctBy(keySelector, shouldApplyFilter, null); 
    } 

    public static IEnumerable<TSource> ConditionalDistinctBy<TSource, TKey>(this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (keySelector == null) throw new ArgumentNullException("keySelector"); 
     if (shouldApplyFilter == null) throw new ArgumentNullException("shouldApplyFilter"); 
     return ConditionalDistinctByImpl(source, keySelector, shouldApplyFilter, comparer); 
    } 

    private static IEnumerable<TSource> ConditionalDistinctByImpl<TSource, TKey>(IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, Func<TKey, bool> shouldApplyFilter, IEqualityComparer<TKey> comparer) 
    { 
     var knownKeys = new HashSet<TKey>(comparer); 
     foreach (var element in source) 
     { 
      var key = keySelector(element); 
      if (shouldApplyFilter(key) && knownKeys.Add(key)) 
      { 
       yield return element; 
      } 
     } 
    } 
} 

Es wäre wie

.ConditionalDistinctBy(m => m.SomeUniqueMovieProperty, s => !String.IsNullOrEmpty(s)); 
+0

Sie ignorieren die Fälle vollständig, wenn SomeUniqueMovieProperty einer String-Repräsentation einer Zufallszahl entspricht;) –

+0

Wenn die Eigenschaft eine von Guid.NewGuid() generierte Guid vorhersagen kann Ich denke, es verdient herausgefiltert werden, es ist zu gefährlich, es ist psychisch;) –

+0

Nits nicht zu wählen, will nur daran erinnern, die op sagt null/leer in Titel –

2

man konnte sie vielleicht verwendet werden, filtern auf einem Verbund verschiedene Schlüssel, wie wie folgt

movies.DistinctBy(m => String.Format({0}{1}{...},m.prop1,m.prop2,[])); 
+0

+ 1 Interessanter Gedanke, leider, dass Eigentum das einzige ist, das zuverlässig genug ist, um Einzigartigkeit zu bestimmen. Wenn du das zuverlässig nennst;) – FailedUnitTest

1

Eine letzte Möglichkeit, die wahrscheinlich übertrieben ist, Sie kann IEqualityComparer implementieren und die Logik dort einfügen, wenn null als eindeutig betrachtet wird. DistinctBy hat nur in diesem Fall eine Überladung.

public class MovieComparer : IEqualityComparer<string> 
{ 

    public bool Equals(string x, string y) 
    { 
     if (x == null || y == null) 
     { 
      return false; 
     } 

     return x == y; 
    } 

    public int GetHashCode(string obj) 
    { 
     if (obj == null) 
     { 
      return 0; 
     } 
     return obj.GetHashCode(); 
    } 
} 
+0

Ist es für einen 'IEqualityComparer' erlaubt,' Equals (x, x) 'return' false' für irgendein 'x' zu machen? [Die Dokumentation] (https://msdn.microsoft.com/en-us/library/ms132154%28v=vs.110%29.aspx) besagt: "Die Equals-Methode ist reflexiv, symmetrisch und transitiv. Das heißt, es gibt true zurück, wenn es verwendet wird, um ein Objekt mit sich selbst [...] zu vergleichen. " – hvd

+0

Wenn dies eine andere Klasse als" string "war, vergewissern Sie sich, dass Sie mit' x == y' vorsichtig sind, können Sie 'Object.Equals verwenden (x, y) 'stattdessen. –

+0

@hvd da dies ein einzigartiger Fall ist, wo sie wollen, dass der gleiche Wert als einzigartig behandelt wird, glaube ich, dass es erlaubt ist. Ich würde dies nicht für einen generischen Vergleich tun, weshalb es eine eigene Klasse mit eigenen Kommentaren sein würde, wenn man sie benutzt. – CharlesNRice

2

Unter der Annahme, m ‚s Equals/GetHashCode nicht außer Kraft gesetzt wird, wenn m.SomeUniqueMoviePropertynull ist, und Sie haben keine andere eindeutigen Schlüssel, können Sie m sich als eindeutigen Schlüssel verwenden.

DistinctBy(m => (object) m.SomeUniqueMovieProperty ?? m) 
Verwandte Themen