我有一个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;
}
我想得到那些演奏不同乐器的人的内部秩序。在MSSQL中我会使用
SELECT
*
,Row_Number() OVER (PARTITION BY inst ORDER BY id) AS rn
FROM Beatles
此查询返回
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);
}
答案 0 :(得分: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 );
}
输出:
Guitar John 1
Guitar George 2
Guitar Paul 3
drums Ringo 1
drums Pete 2
答案 1 :(得分:14)
B&#34; H
我知道这是旧的。但为什么简单的解决方案呢?
var o = beatles.GroupBy(x => x.inst)
.SelectMany(g =>
g.Select((j, i) => new { j.inst, j.name, rn = i + 1 })
);
答案 2 :(得分:5)
另一个想法是使用视图,如果可能的话。
答案 3 :(得分:3)
正如@The_Smallest指出的那样,LINQ不支持行号。以下是您可以获得所需内容的方法:
var grouped = beatles.OrderBy( x => x.id )
.ToList() // required because SelectMany below doesn't evaluate to SQL
.GroupBy( x => x.inst );
var rns = grouped.ToDictionary( x => x.Key, x => 1 );
var result = grouped
.SelectMany( x => x.Select(
y => new { inst = y.inst, name = y.name, rn = rns[y.inst]++ } ) );
答案 4 :(得分:2)
有些人可能会在您的代码中找到有用的方法来获取正确的索引
.Select((item, i) => new { Item = item, Index = i })
答案 5 :(得分:1)
另一种解决方法,相当于RANK()OVER(PARTITION BY“partitionBy”ORDER BY“orderBy”DESC):
DataTable Rank(DataTable dt, string partitionBy, string orderBy, int whichRank)
{
DataView dv = new DataView(dt);
dv.Sort = partitionBy + ", " + orderBy + " DESC";
DataTable rankDt = dv.ToTable();
rankDt.Columns.Add("Rank");
int rank = 1;
for (int i = 0; i < rankDt.Rows.Count - 1; i++)
{
rankDt.Rows[i]["Rank"] = rank;
DataRow thisRow = rankDt.Rows[i];
DataRow nextRow = rankDt.Rows[i + 1];
if (thisRow[partitionBy].ToString() != nextRow[partitionBy].ToString())
rank = 1;
else
rank++;
}
DataView selectRankdv = new DataView(rankDt);
selectRankdv.RowFilter = "rank = " + whichRank;
return selectRankdv.ToTable();
}
答案 6 :(得分:0)
https://github.com/jurioli/Applied
var result = data.GroupBy(a => new { a.inst }).AsPartition()
.Over(p => p.RowNumber(), (a, value) => new { a.inst, a.name, RowNumber = value })
.ToList();