【问题标题】:How do I .OrderBy() and .Take(x) this LINQ query?我如何 .OrderBy() 和 .Take(x) 这个 LINQ 查询?
【发布时间】:2011-07-16 02:39:19
【问题描述】:

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

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

我希望按 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 实际上是一个客户编号。

输出将是一个包含名字、姓氏、日期和记录 ID 的结果集。根据多种因素,每个 recordId 会返回 1 到 5 条记录。

编辑 #2 - .Take(x) 用于记录 ID。每个 recordId 可能有多行。现在,假设我想要每个 recordId 的最新日期。 (按日期降序排序时选择 top(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

【问题讨论】:

  • 你能展示你想要的样子吗?这会有所帮助
  • 按日期对一组记录进行排序是什么意思?是否在同一日期具有相同 recordId 的所有项目?
  • 您想要每个日期的前 N ​​条记录吗?对于每个记录 ID?为了使这个问题有意义,您应该显示一些示例输出。
  • 你能澄清一下 Take 要求吗?您是指每个 RecordId 中的最新 N 吗?还是全球最新的(所有记录)?

标签: c# .net linq


【解决方案1】:

只需添加

.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】:

    您不能那么容易地按不属于 group by 字段的字段进行排序。您会得到每个组的列表。这意味着,您会为每个 recordId 获得一个 date 列表。

    • 您可以按 Max(date) 或 Min(date) 订购。
    • 或者您可以按记录 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)
    

    【讨论】:

      【解决方案3】:

      这似乎与您的其他问题非常相似 - 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...您可以在 Dump() 之前添加这个 .Take(N)

      但是,我不确定这就是您要找的东西?你能澄清你的问题吗?

      【讨论】:

      • 基于同样的问题。由于这是一个不同的问题,我觉得最好接受该问题的 qand anser 并添加一个新问题。
      • 我认为你不能按recordId分组然后按日期排序,因为日期不是结果类型的成员。
      • 请注意,此答案中的代码不做组(问题标题现在也改变了?)
      • 对于 .Take(),我们先来看看变量部分。如何返回前 1 个结果或获取最近的记录?
      • 添加为单独的答案 - 这完全取决于您要寻找的内容 - 祝您好运!
      【解决方案4】:

      如果您想要每个组的前 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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-11
        • 2021-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-17
        相关资源
        最近更新 更多