LINQ由2个属性和创建日期区分

时间:2013-08-15 15:39:14

标签: c# linq sorting distinct

我有一个包含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

问题:

如何获得Rating1Rating2等于给定评级值的列表,以及该列表中最后创建的元素?

我通过样本解释我的意见。假设这是列表:

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.

3 个答案:

答案 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.MinMath.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添加到WhereGroupBy,然后您就完成了。

答案 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();