簡體   English   中英

為什么沒有Linq方法通過謂詞返回不同的值?

[英]Why is there no Linq method to return distinct values by a predicate?

我想在列表中獲取不同的值,但不是通過標准的相等比較。

我想做的是這樣的:

return myList.Distinct( (x, y) => x.Url == y.Url );

我不能,Linq中沒有擴展方法可以做到這一點 - 只需要一個IEqualityComparer

我可以用這個來解決它:

return myList.GroupBy( x => x.Url ).Select( g => g.First() );

但這似乎很混亂。 它也沒有做同樣的事情 - 我只能在這里使用它因為我有一把鑰匙。

我也可以添加自己的:

public static IEnumerable<T> Distinct<T>( 
    this IEnumerable<T> input, Func<T,T,bool> compare )
{
    //write my own here
}

但這似乎就像寫一些應該存在的東西一樣。

任何人都知道為什么這種方法不存在?

我錯過了什么嗎?

當然,這很煩人。 它也是我的“MoreLINQ”項目的一部分,我必須在某些方面注意:)有很多其他操作在投影時有意義,但返回原始--MaxBy和MinBy春天的想法。

正如你所說,它很容易編寫 - 雖然我更喜歡名稱“DistinctBy”來匹配OrderBy等。如果您感興趣,這是我的實現:

    public static IEnumerable<TSource> DistinctBy<TSource, TKey>
        (this IEnumerable<TSource> source,
         Func<TSource, TKey> keySelector)
    {
        return source.DistinctBy(keySelector,
                                 EqualityComparer<TKey>.Default);
    }

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

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

但這似乎很混亂。

它並不凌亂,這是正確的。

  • 如果你想要FirstName的Distinct Programmers並且有四個Amy,你想要哪一個?
  • 如果你按FirstName對程序員進行Group並取First一個,那么在四個Amy的情況下你很清楚你想要做什么。

我只能在這里使用它因為我有一把鑰匙。

您可以使用相同的模式執行多個“不同”鍵:

return myList
  .GroupBy( x => new { x.Url, x.Age } )
  .Select( g => g.First() );

喬恩,你的解決方案非常好。 雖然有一個小的改變。 我認為我們不需要EqualityComparer.Default。 這是我的解決方案(當然,起點是Jon Skeet的解決方案)

    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
    {
        //TODO All arg checks
        HashSet<TKey> keys = new HashSet<TKey>();
        foreach (T item in source)
        {
            TKey key = keySelector(item);
            if (!keys.Contains(key))
            {
                keys.Add(key);
                yield return item;
            }
        }
    }

使用AmyB的答案 ,我編寫了一個小的DistinctBy擴展方法,以允許傳遞謂詞:

/// <summary>
/// Distinct method that accepts a perdicate
/// </summary>
/// <typeparam name="TSource">The type of the t source.</typeparam>
/// <typeparam name="TKey">The type of the t key.</typeparam>
/// <param name="source">The source.</param>
/// <param name="predicate">The predicate.</param>
/// <returns>IEnumerable&lt;TSource&gt;.</returns>
/// <exception cref="System.ArgumentNullException">source</exception>
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source,
     Func<TSource, TKey> predicate)
{
    if (source == null)
        throw new ArgumentNullException("source");

    return source
        .GroupBy(predicate)
        .Select(x => x.First());
}

您現在可以通過以下方式傳遞謂詞以對列表進行分組:

var distinct = myList.DistinctBy(x => x.Id);

或按多個屬性分組:

var distinct = myList.DistinctBy(x => new { x.Id, x.Title });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM