如何使用c#和Linq从下一个列表中获取result
:
var pr = new List<Product>()
{
new Product() {Title="Boots",Color="Red", Price=1},
new Product() {Title="Boots",Color="Green", Price=1},
new Product() {Title="Boots",Color="Black", Price=2},
new Product() {Title="Sword",Color="Gray", Price=2},
new Product() {Title="Sword",Color="Green",Price=2}
};
Result
:
{Title="Boots",Color="Red", Price=1},
{Title="Boots",Color="Black", Price=2},
{Title="Sword",Color="Gray", Price=2}
我知道我应该使用GroupBy
或Distinct
,但要了解如何获得所需内容
List<Product> result = pr.GroupBy(g => g.Title, g.Price).ToList(); //not working
List<Product> result = pr.Distinct(...);
请帮忙
答案 0 :(得分:74)
按所需属性分组,然后选择:
List<Product> result = pr.GroupBy(g => new { g.Title, g.Price })
.Select(g => g.First())
.ToList();
答案 1 :(得分:3)
虽然新的匿名类型可以使用,但它可能更有意义,更具可读性,并且可以在您的方法之外使用,以创建自己的类型或使用Tuple。 (其他时候,使用分隔字符串就足够了:string.Format({0}.{1}, g.Title, g.Price)
)
List<Product> result = pr.GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
.ToList();
List<Product> result = pr.GroupBy(g => new ProductTitlePriceGroupKey(g.Title, g.Price))
.ToList();
至于获得你想要的结果集,提供的答案建议只返回第一个,也许这可以用于你的目的,但理想情况下你需要提供一种方法,Color
被聚合或忽略。
例如,也许您宁愿列出所包含的颜色,不知何故:
List<Product> result = pr
.GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
.Select(x => new Product()
{
Title = x.Key.Item1,
Price = x.Key.Item2,
Color = string.Join(", ", x.Value.Select(y => y.Color) // "Red, Green"
})
.ToList();
对于颜色的简单字符串属性,简单地连接它们可能是有意义的。如果你在那里有另一个实体,或者根本不想抽象出那些信息,那么最好还是让另一个实体拥有该实体类型的集合。例如,如果您对标题和颜色进行分组,则可能需要显示平均价格或一系列价格,只需选择每个组中的第一个就会阻止您这样做。
List<ProductGroup> result = pr
.GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
.Select(x => new ProductGroup()
{
Title = x.Key.Item1,
Price = x.Key.Item2,
Colors = x.Value.Select(y => y.Color)
})
.ToList();
答案 2 :(得分:0)
如果要将某些逻辑抽象为可重用的扩展方法,则可以添加以下内容:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (!seenKeys.Contains(keySelector(element)))
{
seenKeys.Add(keySelector(element));
yield return element;
}
}
}
这将适用于单个属性和复合属性,并返回第一个 匹配元素
// distinct by single property
var productsByTitle = animals.DistinctBy(a => a.Title);
// distinct by multiple properties
var productsByTitleAndColor = animals.DistinctBy(a => new { a.Title, a.Color} );
这种方法的一个好处(而不是先按+分组)是可以返回一个可枚举的可枚举数,以防万一您有后来的标准而又不强迫您遍历整个集合
进一步阅读:linq query to return distinct field values from a list of objects