[英]How do I perform a DISTINCT query using LINQ (.NET 4)?
我有一个对象集,想对集合执行DISTINCT。 返回的对象每个都有大约10个属性。 我想使用这些属性,因此投影确实不是一种选择。 在这10个属性中,我只想将DISTINCT应用于两个字段(DistrictId和ContactId)。 我该怎么做呢?
由于只需要在DistrictId和ContactId组合方面不同的元素,因此可以使用GroupBy
,然后决定要如何处理重复项。 在这种情况下,每个组代表属于一个不同组合的项目。
var results = context.MyCollection
.GroupBy( x=> new { x.DistrictId, x.ContactId })
.Select(...)
我们可以定义一个扩展方法来对T的IEnumerable进行DistinctBy操作,如下所示:
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();
}
}
然后可以在一个简单的Console应用程序中测试DistinctBy运算符,在该应用程序中我们想要获取不同的(模型,颜色)元组,即我们只需要Model + Color组合中的一辆汽车:
课程计划{
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”,因为我们已经有一个黑色的奥迪。 我们没有得到“沃尔沃S90黑色”,因为我们已经有了黑色沃尔沃。 我们都得到了法拉利F500,因为它们有不同的颜色。 遗憾的是,由于“ Lada Limousine Rusty”是模型和颜色的唯一组合,因此我们陷入了困境。
您可以尝试构造匿名类型来处理这种情况。 假设您的具有10个属性的类是Element
public class Element
{
public int FirstProp { get; set; }
public int SecondProp { get; set; }
//others 8 cool properties
}
使用linq中的扩展方法提取所需内容的查询:
IList<Element> element = new List<Element>();
var result = new { P1 = element
.Select(X => X.FirstProp).Distinct()
,
P2 = element
.Select(X => X.SecondProp).Distinct()
,
element
// do projections here over others 8 properties
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.