我如何.OrderBy()和.Take(x)这个LINQ查询?

时间:2011-03-15 20:21:03

标签: c# .net linq

下面的LINQ查询工作正常,但我需要稍微调整一下。

我希望文件中的所有记录按记录ID(客户编号)分组,然后按降序排列日期。我正在进行分组,日期按降序排列。现在,进行调整。

我希望通过recordId按升序对组进行排序。目前,这些组按日期排序,或者看起来如此。我尝试在.GroupBy之后添加.OrderBy,但根本无法使用。

最后,我想要.take(x)记录,其中x依赖于其他一些因素。基本上,.take(x)将返回最近的x记录。我尝试在各个地方放置一个.take(x),但我得不到正确的结果。

var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new 
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = tokens[13],
date = Convert.ToDateTime(tokens[17])
}
)
.OrderByDescending (m => m.date)
.GroupBy (m => m.recordId)
.Dump();

编辑#1 - recordId不是唯一的。可能/可能会有多个记录具有相同的recordId。 recordId实际上是一个客户编号。

输出将是带有名字,姓氏,日期和recordId的结果集。根据几个因素,每个recordId返回的记录多为1到5个。

编辑#2 - .Take(x)用于recordId。每个recordId可能有多行。现在,让我们假设我想要每个recordId的最新日期。 (按日期降序排序时选择顶部(1))

编辑#3 -

以下查询生成以下结果。注意每个recordId只在输出中产生1行(这没关系),看起来它是最近的日期。我还没有彻底检查过这个。

现在,我如何按升序排序,由recordId?

var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new 
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = Convert.ToInt32(tokens[13]),
date = Convert.ToDateTime(tokens[17])
}
)
.GroupBy (m => m.recordId)
.OrderByDescending (m => m.Max (x => x.date ) )
.Select (m => m.First () )
.Dump();


FirstName LastName recordId date 
X      X      2531334      3/11/2011 12:00:00 AM 
X      X      1443809      10/18/2001 12:00:00 AM
X      X      2570897      3/10/2011 12:00:00 AM
X      X      1960526      3/10/2011 12:00:00 AM
X      X      2475293      3/10/2011 12:00:00 AM
X      X      2601783      3/10/2011 12:00:00 AM
X      X      2581844      3/6/2011 12:00:00 AM
X      X      1773430      3/3/2011 12:00:00 AM
X      X      1723271      2/4/2003 12:00:00 AM
X      X      1341886      2/28/2011 12:00:00 AM
X      X      1427818      11/15/1986 12:00:00 AM

4 个答案:

答案 0 :(得分:1)

您不能轻易地通过不属于分组字段的字段进行排序。您将获得每个组的列表。这意味着,每个date都会获得recordId的列表。

  • 您可以按Max(日期)或Min(日期)订购。
  • 或者您可以按记录ID和日期分组,并按日期排序。

按最近的日期排序:

.GroupBy (m => m.recordId)
// take the most recent date in the group
.OrderByDescending (m => m.Max(x => x.date))
.SelectMany(x => x.First

Take部分是另一个问题。您只需将Take(x)添加到表达式中,然后就可以获得此组数。

修改

对于某种select top(1)

.GroupBy (m => m.recordId)
// take the most recent date in the group
.OrderByDescending (m => m.Max(x => x.date))
// take the first of each group, which is the most recent
.Select(x => x.First())
// you got the most recent record of each recordId 
// and you can take a certain number of it.
.Take(x);

在我的回答中,我已经嗤之以鼻,根据你现在的问题你不会需要它:

// create a separate group for each unique date and recordId
.GroupBy (m => m.date, m => m.recordId)
.OrderByDescending (m => m.Key)

答案 1 :(得分:0)

只需添加

.OrderBy( g=> g.Key);
分组后

。这将按RecordId升序订购groupings

  

最后,我想.take(x)记录在哪里   x取决于其他一些因素。   基本上,.take(x)将返回   最新的x记录。

如果您的日期是“最近的”,那么您为什么要首先按RecordId进行分组 - 只按日期降序排序:

..
.OrderByDescending (m => m.date)
.Take(x)
.Dump();

如果您只想按照分组建立的顺序获取前x个记录,但您可以执行以下操作:

...
.GroupBy (m => m.recordId)
.SelectMany(s => s)
.Take(x)
.Dump();

答案 2 :(得分:0)

这似乎与您的其他问题非常相似 - Reading a delimted file using LINQ

我不相信你想在这里使用Group--我相信你想要使用OrderBy和ThenBy - 比如:

var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new 
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = tokens[13],
date = Convert.ToDateTime(tokens[17])
}
)
.OrderBy (m => m.recordId)
.ThenByDescending (m => m.date)
.Dump();

对于一个简单的Take ...你可以在.Take(N)之前添加Dump()

但是,我不确定这是你在寻找什么?你能澄清一下你的问题吗?

答案 3 :(得分:0)

如果你想要每个组的前3个,那么我认为你需要使用嵌套查询,如:

var recipients = File.ReadAllLines(path)
             .Select(record => record.Split('|'))
             .Select(tokens => new
             {
                 FirstName = tokens[2],
                 LastName = tokens[4],
                 RecordId = tokens[13],
                 Date = Convert.ToDateTime(tokens[17])
             }
             )
             .GroupBy(m => m.RecordId)
             .Select(grouped => new 
             {
                 Id = grouped.Key,
                 First3 = grouped.OrderByDescending(x => x.Date).Take(3)
             }
             .Dump();

如果您希望将其展平为记录列表,则可以使用SelectMany:

var recipients = var recipients = File.ReadAllLines(path)
             .Select(record => record.Split('|'))
             .Select(tokens => new
             {
                 FirstName = tokens[2],
                 LastName = tokens[4],
                 RecordId = tokens[13],
                 Date = Convert.ToDateTime(tokens[17])
             }
             )
             .GroupBy(m => m.RecordId)
             .Select(grouped => grouped.OrderByDescending(x => x.Date).Take(3))
             .SelectMany(item => item)
             .Dump();