1

映画のリストがあり、それらを別のリストとマージして複製する必要があります。

DistinctBy(m => m.SomeUniqueMovieProperty)これを達成するためにJon Skeet'sを使用していますが、問題なく動作します。DistinctByただし、映画の 10 ~ 20% (いずれかのリスト) でこのプロパティが入力されておらず、 1 つの幸運な映画に折りたたまれている場合があることがすぐにわかりました。

これは問題です。このプロパティの値を持たないすべてのムービーを保持したいのです。最初は、各コレクションからこれらのムービーを抽出し、複製してから再度マージすることを考えていましたが、この問題に対するより短い解決策はありますか?

4

5 に答える 5

3

すべての null を含めたい場合は、null プロパティを null の場合に一意のものに置き換える必要があります。プロパティが文字列であると仮定すると、Guid はこの仕事に適しています。

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

null 値を持つプロパティにヒットするたびに、ランダムな新しい GUID 値が入力されます。


空のタイトルも削除されないようにする場合は、クエリを次のように変更します

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

もう 1 つのオプションは、希望DistinctByどおりに動作する独自のものを作成することです。これは元のソースを微調整したバージョンで、true を返す場合にのみフィルターを適用しますshouldApplyFilter。簡潔にするためにコメントも削除されています。

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

次のように使用されます

.ConditionalDistinctBy(m => m.SomeUniqueMovieProperty, s => !String.IsNullOrEmpty(s));
于 2016-06-20T20:00:48.213 に答える
2

おそらく、次のように、複合個別キーでそれらをフィルタリングできます

movies.DistinctBy(m => String.Format({0}{1}{...},m.prop1,m.prop2,[]));
于 2016-06-20T20:04:28.220 に答える
2

mEquals/GetHashCodeがオーバーライドされていないと仮定すると、オーバーライドされていて、他に一意のキーがない場合m.SomeUniqueMoviePropertyは、それ自体を一意のキーとして使用できます。nullm

DistinctBy(m => (object) m.SomeUniqueMovieProperty ?? m)
于 2016-06-20T20:28:45.350 に答える
1

最後の 1 つの方法は、おそらくやり過ぎですが、IEqualityComparer を実装し、null が一意と見なされる場合にロジックをそこに配置できます。DistinctBy には、まさにこの場合のオーバーロードがあります。

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();
    }
}
于 2016-06-20T20:20:16.857 に答える