Linq中的Row_number(分区xxx)?

Roy*_*mir 36 c# linq .net-4.0

我有一个DataTable具有这种结构和数据:

id |   inst   |   name
------------------------
 1 |  guitar  |  john
 2 |  guitar  |  george
 3 |  guitar  |  paul
 4 |  drums   |  ringo
 5 |  drums   |  pete

我可以检索这样的记录:

IEnumerable <Beatle>...

class Beatle
{
  int id;
  string inst;
  string name;
}
Run Code Online (Sandbox Code Playgroud)

我想获得那些演奏不同乐器的人的内部秩序.在MSSQL我会用

SELECT 
    *
    ,Row_Number() OVER (PARTITION BY inst ORDER BY id) AS rn
FROM Beatles
Run Code Online (Sandbox Code Playgroud)

此查询返回

id |   inst   |   name  | rn
-----------------------------
 1 |  guitar  |  john   | 1
 2 |  guitar  |  george | 2
 3 |  guitar  |  paul   | 3
 4 |  drums   |  ringo  | 1
 5 |  drums   |  pete   | 2

我怎么能在Linq那样做?

编辑.(接受答案后)

完整的工作代码:

var beatles = (new[] { new { id=1 , inst = "guitar" , name="john" },
    new { id=2 , inst = "guitar" , name="george" },
    new { id=3 , inst = "guitar" , name="paul" },
    new { id=4 , inst = "drums" , name="ringo" },
    new { id=5 , inst = "drums" , name="pete" }
});

var o = beatles.OrderBy(x => x.id).GroupBy(x => x.inst)
               .Select(g => new { g, count = g.Count() })
               .SelectMany(t => t.g.Select(b => b)
                                   .Zip(Enumerable.Range(1, t.count), (j, i) => new { j.inst, j.name, rn = i }));

foreach (var i in o)
{
    Console.WriteLine("{0} {1} {2}", i.inst, i.name, i.rn);
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ois 33

尝试这一个班轮:

var o = beatles
    .OrderBy( x => x.id )
    .GroupBy( x => x.inst )
    .Select( group => new { Group = group, Count = group.Count() } )
    .SelectMany( groupWithCount =>
        groupWithCount.Group.Select( b => b)
        .Zip(
            Enumerable.Range( 1, groupWithCount.Count ),
            ( j, i ) => new { j.inst, j.name, RowNumber = i }
        )
    );

foreach (var i in o)
{
    Console.WriteLine( "{0} {1} {2}", i.inst, i.name, i.RowNumber );
}
Run Code Online (Sandbox Code Playgroud)

输出:

Guitar John 1
Guitar George 2
Guitar Paul 3
drums Ringo 1
drums Pete 2
Run Code Online (Sandbox Code Playgroud)

  • 这是我在一个班轮上见过的最多线路 (7认同)
  • 我很好奇这会产生什么样的SQL,如果EF支持这个. (3认同)
  • 这仅适用于 Linq to object,但不适用于 Linq to Entities。邮编无法转换。 (3认同)
  • 注意`.GroupBy`,因为.NET字符串比较区分大小写,而SQL不会.如果你有`guitar`和`Guitar`,那么与SQL相比,你会得到不同的结果.在分组字符串时,请参阅此SO帖子以获取选项:http://stackoverflow.com/questions/16190180/case-insensitive-group-on-multiple-columns (2认同)

Rab*_*bbi 15

B"H

我知道这是旧的.但为什么解决方案不简单呢?

var o = beatles.GroupBy(x => x.inst)
               .SelectMany(g =>
                   g.Select((j, i) => new { j.inst, j.name, rn = i + 1 })
               );
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于 Linq to object,但不适用于 Linq to Entities。 (9认同)
  • 如果需要明确的顺序,那么代码可以扩展为 `code` var o = beatles .GroupBy(x =&gt; x.inst) .SelectMany(g =&gt; g.OrderBy(x =&gt; x.name).Select( (j, i) =&gt; new { j.inst, j.name, rn = i + 1 })); `代码` (4认同)

lep*_*pie 5

另一个想法是使用视图,如果可能的话.