对组进行排序以按包含元素的日期显示它们(LINQ)

时间:2014-02-11 07:16:03

标签: linq sorting linq-group

我不确定这是否可行。 我的班级我有一个这样的列表:

class Person
{
 string Firstname
 string Lastname
 DateTime Timestamp
}

现在我想创建群组 名字姓氏

  • John Deer,3:12
  • John Deer,6:34
  • John Deer,11:12
  • Tom Kin,1:12
  • Tom Kin,3:49
  • Tom Kin,4:22
  • Markus Fert,11:23

我还希望排序这些群组的时间戳,最后应该是第一个,而群组应保持显示在listView。

  • Markus Fert(群组标题)
    11:23(内容元素)

  • John Deer
    11:12
    6:34

  • 汤姆健
    4:22
    3:49

  • John Deer
    3:12

  • 汤姆健
    1:22

希望任何Linq天才能帮我解决问题:) 谢谢!


非常感谢谢尔盖,工作就像一个魅力!

此外,我想为我的群组密钥创建自定义类,以在我的ListView标头中显示不同的其他内容。 (不仅是拼接在一起的字符串)

我想将我的查询分配给这样的IEnumerable:

IEnumerable<IGrouping<Header, Person>> PersonGroups 

标题包含每个Person中包含的一些其他属性(例如,每个Person还有一个Country,Age,...)。也许你也可以帮助我吗?


再次感谢谢尔盖。通过实现实现ICompareable接口的Header类解决了我的问题。

IEnumerable<IGrouping<Header, Person>> PersonGroups

 public class Header: IComparable<Header>
 {
     public Header(string firstname, string lastname)
     {
        Firstname= firstname;
        Lastname = lastname;
     }

     public string Firstname{ get; set; }
     public string Lastname{ get; set; }

     public int CompareTo(Header that)
     {
       if (this.Firstname == that.Firstname&& this.Lastname == that.Lastname)
          return 0;
       else
           return -1;
     }
  }

我的查询现在看起来像这样:

PersonGroups= persons.OrderByDescending(p => p.Timestamp)
                .GroupConsecutive(p => new Header(p.Firstname, p.Lastname));

2 个答案:

答案 0 :(得分:1)

实际上,您需要先按时间戳排序结果。然后才由连续的人对这个有序序列进行分组:

var query = 
  people.OrderByDescending(p => p.Timestamp.TimeOfDay)
        .GroupConsecutive(p => String.Format("{0} {1}", p.Firstname, p.Lastname))
        .Select(g => new {
             Header = g.Key,
             Content = String.Join("\n", g.Select(p => p.Timestamp.TimeOfDay))
        });

您需要GroupConsecutive实现,它会根据提供的选择器的相同值(在您的情况下为全名)创建连续项目组。

对于您的样本输入结果是:

[
  {
    "Header": "Markus Fert",
    "Content": "11:23:00"
  },
  {
    "Header": "John Deer",
    "Content": "11:12:00\n06:34:00"
  },
  {
    "Header": "Tom Kin",
    "Content": "04:22:00\n03:49:00"
  },
  {
    "Header": "John Deer",
    "Content": "03:12:00"
  },
  {
    "Header": "Tom Kin",
    "Content": "01:12:00"
  }
]

答案 1 :(得分:0)

以下是使用内置链接运算符Aggregate的方法。

首先,我需要通过降序时间戳来对列表进行排序,然后创建一个名称格式化函数。

var op = people
    .OrderByDescending(p => p.Timestamp)
    .ToArray();

Func<Person, string> toName = p =>
    String.Format("{0} {1}", p.Firstname, p.Lastname);

现在我可以构建查询:

var query =
    op
        .Skip(1)
        .Aggregate(new []
        {
            new
            {
                Name = toName(op.First()),
                Timestamps = new List<string>()
                {
                    op.First().Timestamp.ToShortTimeString(),
                },
            },
        }.ToList(), (a, p) =>
        {
            var name = toName(p);
            if (name == a.Last().Name)
            {
                a.Last().Timestamps.Add(p.Timestamp.ToShortTimeString());
            }
            else
            {
                a.Add(new
                {
                    Name = name,
                    Timestamps = new List<string>()
                    {
                        p.Timestamp.ToShortTimeString(),
                    },
                });
            }
            return a;
        });

我得到了这个结果:

result