C# Linq中(由xxx划分)上的行数?

C# Linq中(由xxx划分)上的行数?,c#,linq,.net-4.0,C#,Linq,.net 4.0,我有一个DataTable,它具有以下结构和数据: id | inst | name ------------------------ 1 | guitar | john 2 | guitar | george 3 | guitar | paul 4 | drums | ringo 5 | drums | pete 此查询返回 id | inst | name | rn ----------------------------

我有一个
DataTable
,它具有以下结构和数据:

id | inst | name ------------------------ 1 | guitar | john 2 | guitar | george 3 | guitar | paul 4 | drums | ringo 5 | drums | pete 此查询返回

id | inst | name | rn ----------------------------- 1 | guitar | john | 1 2 | guitar | george | 2 3 | guitar | paul | 3 4 | drums | ringo | 1 5 | drums | pete | 2
正如@The_所指出的,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]++ } ) );

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

试试这一行:

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

有些人可能会发现在代码中使用适当的索引很有用

.Select((item, i) => new { Item = item, Index = i })

另一个解决方案是对(按“partitionBy”按“orderBy”按“orderBy”DESC进行分区)执行RANK()的等效操作:

DataTable秩(DataTable dt、string partitionBy、string orderBy、int whichRank)
{
数据视图dv=新数据视图(dt);
dv.Sort=partitionBy+,“+orderBy+”DESC”;
DataTable rankDt=dv.ToTable();
rankDt.Columns.Add(“秩”);
int秩=1;
对于(int i=0;i
Linq to对象的另一个解决方案是:

var result = beatles
            .GroupBy(g => g.inst)
            // PARTITION BY ^^^^
            .Select(c => c.OrderBy(o => o.id).Select((v, i) => new { i, v }).ToList())
            //                   ORDER BY ^^
            .SelectMany(c => c)
            .Select(c => new { c.v.id, c.v.inst, c.v.name, rn = c.i + 1 })
            .ToList();
B“H

我知道这很古老,但为什么解决方案不简单呢

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


Linq2SQL或EF?不确定这两种方式是否有区别:)如果我理解正确,考虑到带有索引参数的Select重载,这应该不会很困难。
y=>new{y.inst,y.name,rn=rns[y.inst]+}
不是表达式,这就是它不会编译为sql查询的原因。遗憾的是,该查询将在本地执行,sql没有任何好处。好吧,您可以将其全部拖到内存中,在内存中工作。请参阅上面的更新。是的,正如您所说,sql没有任何好处。如果您想利用sql,您必须,正如下面@u所指出的,创建一个存储的procedure.@c.sokun:t“是一个包含在
语句中生成的匿名类型的变量。请选择
语句。”。因此,保持分组计数。@JonComtois我是在伤脑筋为什么
selectmany
之后才知道
t
,然后我意识到它是在
select
之后,而不是在
selectmany
之后。为澄清而编辑。:-)如果EF支持,我很好奇这会生成什么样的SQL。请注意
.GroupBy
,因为.NET字符串比较区分大小写,而SQL则不区分大小写。如果您有
吉他
吉他
,您将得到与SQL不同的结果。在对字符串进行分组时,请参阅本文:这是我在单行中见过的最多行。如果需要明确的顺序,那么代码可以扩展到
code
var o=beatles.GroupBy(x=>x.inst)。SelectMany(g=>g.OrderBy(x=>x.name)。Select((j,I)=>new{j.inst,j.name,rn=I+1})<代码>代码
.Select((item, i) => new { Item = item, Index = i })
 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();
  }
var result = beatles
            .GroupBy(g => g.inst)
            // PARTITION BY ^^^^
            .Select(c => c.OrderBy(o => o.id).Select((v, i) => new { i, v }).ToList())
            //                   ORDER BY ^^
            .SelectMany(c => c)
            .Select(c => new { c.v.id, c.v.inst, c.v.name, rn = c.i + 1 })
            .ToList();
var o = beatles.GroupBy(x => x.inst)
               .SelectMany(g =>
                   g.Select((j, i) => new { j.inst, j.name, rn = i + 1 })
               );
var result = data.GroupBy(a => new { a.inst }).AsPartition()
.Over(p => p.RowNumber(), (a, value) => new { a.inst, a.name, RowNumber = value })
.ToList();