我有几个看起来像这样的类(简化为SO):
public class Result
{
pubic List<Review> Reviews { get; set; }
}
public class Review
{
public string Name { get; set; }
public int Amount { get; set; }
}
我开始的是一个List<Result>
对象。列表中的每个“Result”对象显然都有另一个List属性。在每个“结果”对象中,其评论列表将永远不会有重复的“名称”属性。但是,存在预期的情况,即列表中的所有Result对象都将存在重复的“Name”属性。
例如:
var results = new List<Result>();
var result1 = new Result();
result1.Reviews = new List<Review>();
result1.Reviews.Add(new Review { Name = "ABC", Amount = 5 });
result1.Reviews.Add(new Review { Name = "DEF", Amount = 4 });
results.Add(result1);
var result2 = new Result();
result2.Reviews = new List<Review>();
result2.Reviews.Add(new Review { Name = "ABC", Amount = 1 });
result2.Reviews.Add(new Review { Name = "WRA", Amount = 4 });
results.Add(result2);
var result3 = new Result();
result3.Reviews = new List<Review>();
result3.Reviews.Add(new Review { Name = "ABC", Amount = 2 });
result3.Reviews.Add(new Review { Name = "ARA", Amount = 4 });
results.Add(result3);
因此,您可以在结果列表中看到名称“ABC”在评论列表中重复。我需要做的是编写一个LINQ查询,对results
对象进行操作,该对象将从子列表中删除所有重复的Review对象,除了最高的一个。因此,在这种情况下,result2和result3都会从列表中完全删除它们的“ABC”评论。
有关如何使用LINQ执行此操作的任何建议?我也在寻找自己的解决方案,我想在这里发帖看看它是否比我自己搞定更快。 :)
答案 0 :(得分:0)
不要使用Reviews
的公共属性,而应使用私有属性。然后提供您自己的add()
方法,并插入或替换元素。
修改结果的Equals
方法,以便在名称匹配时,结果的线程为“相等”。 (这是不正确的,但是在检查项目存在时,contains()
和indexOf()
的工作方式是我们想要它的工作方式):
public class Review
{
public string Name { get; set; }
public int Amount { get; set; }
public override bool Equals(System.Object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
Review r = obj as Review;
if ((System.Object)r == null)
{
return false;
}
//only compare on the name.
return Name.Equals(r.Name);
}
}
现在,结果和添加方法:
class Result
{
private List<Review> _Reviews = new List<Review>();
public List<Review> Reviews { get { return _Reviews; } }
public void Add(Review r)
{
if (_Reviews.Contains(r))
{
//check if difference on Amount
int index = _Reviews.IndexOf(r);
Review currentReview = _Reviews[index];
if (currentReview.Amount < r.Amount)
{
//replace
_Reviews.RemoveAt(index);
_Reviews.Add(r);
}
//else keep existing
}
else
{
//Add
_Reviews.Add(r);
}
}
}
最后,您可以将每个评论添加到相同的结果中,而无需处理任何事情:
var result = new Result();
result.Add(new Review { Name = "ABC", Amount = 5 });
result.Add(new Review { Name = "DEF", Amount = 4 });
result.Add(new Review { Name = "ABC", Amount = 1 });
result.Add(new Review { Name = "WRA", Amount = 4 });
result.Add(new Review { Name = "ABC", Amount = 2 });
result.Add(new Review { Name = "ARA", Amount = 4 });
foreach (Review r in result.Reviews)
{
MessageBox.Show(r.Name + ": " + r.Amount);
}
无论您提供add-calls的顺序,包含的元素都是:
ABC:5
DEF:4
WRA:4
ARA:4
(如果需要,按名称排序)
答案 1 :(得分:0)
这将为您提供所有已过滤的评论的数量,以排除除最大重复之外的所有内容。然后,您可以随意处理它们。
results
.SelectMany(l => l.Reviews) // flattens the lists
.GroupBy(r => r.Name) // groups all reviews of the same thing together
.Select(g => new Review {Name = g.Key, Amount = g.Max(x => x.Amount)}) // select only the highest of each group
答案 2 :(得分:0)
如果您想获取Result
s:
List<Result> newList = results.SelectMany(res => res.Reviews.Select(r => new { Result = res, Review = r }))
.GroupBy(pair => pair.Review.Name)
.Select(grp => grp.First())
.GroupBy(pair => pair.Result, pair => pair.Review)
.Select(reviews =>
{
// Here you can create new Result object of use the original one
Result result = reviews.Key; // Here is original Result object
result.Reviews = reviews.ToList(); // Replacing Reviews list with the filtered one
return result;
})
.ToList();
此查询的缺点是它会删除没有评论的结果。
如果您不需要原始Result对象,则可以使用查询的简化版本:
List<Result> newList = results.SelectMany(res => res.Reviews)
.GroupBy(r => r.Name)
.Select(grp => grp.First())
.ToList();
答案 3 :(得分:0)
这是一个详细的解决方案,但它会产生您的要求:
var rev = results.SelectMany(r => r.Reviews).GroupBy(n => n.Name).Where(c => c.Count() > 1);
foreach (var item in rev)
{
Review review = results.SelectMany(r => r.Reviews).First(x => x.Name == item.Key);
results.ForEach(r => r.Reviews.RemoveAll(re => re.Name == item.Key && !re.Equals(review)));
}
这将删除第一次出现的所有重复项。
答案 4 :(得分:0)
您可以使用SelectMany
从所有结果中获取所有评价的统一序列,您可以按名称对这些评论进行分组,过滤掉包含多个项目的组,选择所有结果第一个之后的项目,然后从结果中删除所有这些评论。
在查询语法中执行所有这些操作比在方法语法中更方便。
var query = from result in results
from review in result.Reviews
group new { result, review } by review.Name into matches
where matches.Count() > 1
from match in matches
.OrderByDescending(match => match.review.Amount)
.Skip(1)
select match;
foreach (var match in query)
match.result.Reviews.Remove(match.review);