Мы можем определить метод расширения для выполнения операции DistinctBy для IEnumerable с T, как показано ниже:
public static class EnumerableExtensions
{
/// <summary>
/// Returns a ienumerable which is distinct by a given property key selector. If a custom equality
/// comparer is to be used, pass this in as the comparer. By setting the comparer default to null,
/// the default comparer is used.
/// </summary>
/// <typeparam name="T">The item type in the ienumerable</typeparam>
/// <typeparam name="TKey">The type of the key selector (property to disinct elements by)</typeparam>
/// <param name="coll">The source ienumerable</param>
/// <param name="keySelector">The key selector, use a member expression in a lambda expression</param>
/// <param name="comparer">Custom comparer to use, pass in null here to specify that default comparer is used,
/// however, this is default set to null and not required parameter</param>
/// <returns></returns>
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> coll, Func<T, TKey> keySelector,
IEqualityComparer<TKey> comparer = null)
{
if (coll == null)
throw new ArgumentNullException("coll");
if (keySelector == null)
throw new ArgumentNullException("keySelector");
var result = coll.GroupBy(keySelector, comparer).Select(g => g.First()).ToList();
return new List<T>(result).AsEnumerable();
}
}
Оператор DistinctBy затем можно протестировать, например, в простом консольном приложении, где нам нужночтобы получить различные (модель, цвет) кортежи, то есть мы хотим, чтобы только один автомобиль сочетал модель + цвет:
Программа класса {
static void Main(string[] args)
{
var cars = new []
{
new Car {Model = "Audi", Make = "A4", Color = "Black"},
new Car {Model = "Audi", Make = "A8", Color = "Red"},
new Car {Model = "Audi", Make = "TT", Color = "Black"},
new Car {Model = "Volvo", Make = "XC90", Color = "Black"},
new Car {Model = "Volvo", Make = "S90", Color = "Black"},
new Car {Model = "Ferrari", Make = "F500", Color = "Yellow"},
new Car {Model = "Ferrari", Make = "F500", Color = "Red"},
new Car {Model = "Lada", Make = "Limousine", Color = "Rusty"}
};
var groupedCars = cars.DistinctBy(c => new {c.Model, c.Color});
foreach (var gc in groupedCars)
{
Console.WriteLine(gc.ToString());
}
Console.WriteLine("Press any key to continue ...");
Console.ReadKey();
}
// Define other methods and classes here
}
В таком случае получается:
Model: Audi, Make: A4, Color: Black
Model: Audi, Make: A8, Color: Red
Model: Volvo, Make: XC90, Color: Black
Model: Ferrari, Make: F500, Color: Yellow
Model: Ferrari, Make: F500, Color: Red
Model: Lada, Make: Limousine, Color: Rusty
Press any key to continue ...
Мы не получили предмет «Audi TT Black», потому что у нас уже есть черная Audi.Мы не получили "Volvo S90 Black", потому что мы уже получили черный Volvo.Мы получили оба Ferrari F500, потому что они получили разные цвета.И, к сожалению, мы застряли с «Lada Limousine Rusty», так как это была единственная комбинация модели и цвета.