[英]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;
}
}
}
但這似乎很混亂。
它並不凌亂,這是正確的。
Distinct
Programmers並且有四個Amy,你想要哪一個? 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<TSource>.</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.