我有一个包含Person
模型的列表,如下所示:
public class Person
{
[Key]
public int Id { get; set; }
public int Rating1 { get; set; }
public int Rating2 { get; set; }
public DateTime CreateDate { get; set; }
}
Rating1
永远不等于Rating2
。
问题:
如何获得Rating1
或Rating2
等于给定评级值的列表,以及该列表中最后创建的元素?
我通过样本解释我的意见。假设这是列表:
Rating1 Rating2 CreateDate
4 8 2013-08-15 05:12:00
9 4 2013-08-15 07:12:00
8 4 2013-08-15 08:12:00
5 20 2013-08-15 09:12:00
20 4 2013-08-15 10:12:00
20 5 2013-08-15 11:12:00
4 9 2013-08-15 12:12:00
假设我将评级值'4'作为此方法的参数发送
public IEnumerable<Person> GetList1(int r) {}
并获取一个清单:
8 4 2013-08-15 08:12:00 //because there are many [4 and 8] couples, but this created last.
4 9 2013-08-15 12:12:00 //because there are many [4 and 9] couples, but this created last.
20 4 2013-08-15 10:12:00 //because there is one [4 and 20] couple, this also created last.
如果我将评级值“20”作为GetList1()
方法的参数发送,我想获得一个列表:
20 5 2013-08-15 11:12:00 //because there are many [20 and 5] couples, but this created last.
20 4 2013-08-15 10:12:00 //because there is one [20 and 4] couple, this also created last.
答案 0 :(得分:5)
应该是:
int r = 4; // your rating
var res = from p in lst
where p.Rating1 == r || p.Rating2 == r
group p by new { Min = Math.Min(p.Rating1, p.Rating2), Max = Math.Max(p.Rating1, p.Rating2) };
var res2 = res.Select(p => p.OrderByDescending(q => q.CreateDate).First());
我使用Math.Min
和Math.Max
将最低等级评为第一个,最高等级为第二个。因此4, 8
相当于8, 4
或者,(或多或少等同于):
var res = from p in lst
where p.Rating1 == r || p.Rating2 == r
group p by new { Min = Math.Min(p.Rating1, p.Rating2), Max = Math.Max(p.Rating1, p.Rating2) } into q
select q.OrderByDescending(s => s.CreateDate).First();
或纯LINQ(但不太可读)
var res = from p in lst
where p.Rating1 == r || p.Rating2 == r
group p by new { Min = Math.Min(p.Rating1, p.Rating2), Max = Math.Max(p.Rating1, p.Rating2) } into q
select (from s in q orderby s.CreateDate descending select s).First();
答案 1 :(得分:1)
您可以对两个评级的数组进行分组,这两个评级已经过排序,以获得具有该唯一评级对的项目。
public IEnumerable<Person> GetList1(IEnumerable<Person> source, int rating) {
return source.Where(person => person.Rating1 == rating
|| person.Rating2 == rating)
.GroupBy(person => new int[] { person.Rating1, person.Rating2 }
.OrderBy(r => r), new SequenceComparer<int>())
.Select(group => group.OrderByDescending(p => p.CreateDate)
.First());
}
你需要这个比较器能够在GroupBy
中按照它们的值而不是它们的引用来比较数组:
public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<T> obj)
{
unchecked
{
return obj.Take(5).Aggregate(37,
(acc, item) => acc * 79 + item.GetHashCode());
}
}
}
请注意,此答案优于使用Min
/ Max
来“排序”值的答案的主要优点是,它可以有效地扩展到N个不同的相关字段。如果您添加Rating3
,则需要将该OR添加到Where
和GroupBy
,然后您就完成了。
答案 2 :(得分:0)
var things=new[] {
new {Rating1=4,Rating2=8,CreateDate=DateTime.Parse("2013-08-15 05:12:00")},
new {Rating1=9,Rating2=4,CreateDate=DateTime.Parse("2013-08-15 07:12:00")},
new {Rating1=8,Rating2=4,CreateDate=DateTime.Parse("2013-08-15 08:12:00")},
new {Rating1=5,Rating2=20,CreateDate=DateTime.Parse("2013-08-15 09:12:00")},
new {Rating1=20,Rating2=4,CreateDate=DateTime.Parse("2013-08-15 10:12:00")},
new {Rating1=20,Rating2=5,CreateDate=DateTime.Parse("2013-08-15 11:12:00")},
new {Rating1=4,Rating2=9,CreateDate=DateTime.Parse("2013-08-15 12:12:00")}
};
int r=4;
var result=things
.Where(t=>t.Rating1==r || t.Rating2==r)
.GroupBy(t=>new {r1=Math.Min(t.Rating1,t.Rating2),r2=Math.Max(t.Rating1,t.Rating2)},
(key,group)=>group.OrderByDescending(c=>c.CreateDate).First());
result.Dump();