LINQ:添加RowNumber列

如何修改下面的查询以包含行号列(即:基于一个结果的索引)?

var myResult = from currRow in someTable where currRow.someCategory == someCategoryValue orderby currRow.createdDate descending select currRow; 

编辑1:我正在寻找{idx, col1, col2...col-n}而不是{idx, row}

EDIT2:行号应对应于结果行而不是表行。

EDIT3:我将这些结果DataBindGridView 。 我的目标是向GridView添加行号列。 也许一种不同的方法会更好。

使用方法 – 语法,其中Enumerable.Select与索引重载:

 var myResult = someTable.Select((r, i) => new { Row = r, Index = i }) .Where(x => x.Row.someCategory == someCategoryValue) .OrderByDescending(x => x.Row.createdDate); 

请注意,此方法假定您需要表中行的原始索引而不是过滤结果,因为我在使用Where过滤之前选择了索引。

编辑:我正在寻找{idx,col1,col2 … col-n}而不是{idx,row}的结果。 行号应对应于结果行而不是表行。

然后选择包含所需列的匿名类型:

 var myResult = someTable.Where(r => r.someCategory == someCategoryValue) .OrderByDescending(r => r.createdDate) .Select((r, i) => new { idx = i, col1 = r.col1, col2 = r.col2, ...col-n = r.ColN }); 

使用此Select方法:

通过合并元素的索引,将序列的每个元素投影到新的forms中。

例:

 var myResult = someTable.Where(currRow => currRow.someCategory == someCategoryValue) .OrderByDescending(currRow => currRow.createdDate) .Select((currRow, index) => new {Row = currRow, Index = index + 1}); 

为了回应您的编辑:

如果您想要DataTable作为结果,您可以通过简单地使用DataView并以后添加其他列来采用非Linq方式。

 someTable.DefaultView.RowFilter = String.Format("someCategory = '{0}'", someCategoryValue); someTable.DefaultView.Sort = "createdDate"; var resultTable = someTable.DefaultView.ToTable(); resultTable.Columns.Add("Number", typeof(int)); int i = 0; foreach (DataRow row in resultTable.Rows) row["Number"] = ++i; 

只是为了好玩,这里有两个参数Select

 var resultsWithIndexes = myResult.Zip(Enumerable.Range(1, int.MaxValue - 1), (o, i) => new { Index = i, Result = o }); 

关于什么?

 int i; var myResult = from currRow in someTable where currRow.someCategory == someCategoryValue orderby currRow.createdDate descending select new {Record = i++, currRow}; 

根据你编辑1. 不,你不能 Linq按原样返回表。 您可以构建每个列,但是会失去映射实体的function。

之前已经多次询问过这个问题: 如何为Linq结果添加索引字段

如果想要保持列的平面列表(即OP的Edit2)并且还想要一个适用于任何IEnumerable的通用解决方案而不要求列出预期列的集合,则没有直接的方法。

然而,有一种迂回的方式可以解决它,即使用ToDataTable()方法将查询结果转储到DataTable中,然后将RowNumber列添加到该表中。

 var table = query.ToList().ToDataTable(); table.Columns.Add("RowNum", typeof(int)); int i = 0; foreach (DataRow row in table.Rows) row["RowNum"] = ++i; 

这可能会导致大型数据集的性能问题,但它也不会非常缓慢。 在我的机器上,一个包含约6500行的数据集需要33毫秒才能处理。

如果您的原始查询返回了匿名类型,那么该类型定义将在转换中丢失,因此当您调用table.AsEnumerable()时,您将失去对生成的IEnumerable的列名称的静态类型。 换句话说,不是能够编写类似table.AsEnumerable()。First()。RowNum而是必须编写table.AsEnumerable()。First()[“RowNum”]

但是,如果您不关心性能并且确实希望恢复静态类型,则可以使用JSON.NET将DataTable转换为json字符串,然后根据原始查询结果中的匿名类型将其转换回列表。 此方法需要占位符RowNum字段存在于原始查询结果中。

 var query = (from currRow in someTable where currRow.someCategory == someCategoryValue orderby currRow.createdDate descending select new { currRow.someCategory, currRow.createdDate, RowNum = -1 }).ToList(); var table = query.ToDataTable(); //Placeholder RowNum column has to already exist in query results //So not adding a new column, but merely populating it int i = 0; foreach (DataRow row in table.Rows) row["RowNum"] = ++i; string json = JsonConvert.SerializeObject(table); var staticallyTypedList = JsonConvert.DeserializeAnonymousType(json, query); Console.WriteLine(staticallyTypedList.First().RowNum); 

这为我的6500项目数据集的处理时间增加了大约120ms。

这很疯狂,但它确实有效。

我知道我迟到了,但我想展示一下对我有用的东西。

我有一个对象列表,对象上有一个整数属性,用于“行号”……或者在这种情况下,“序列号”。 这就是我填充该字段所做的事情:

 myListOfObjects = myListOfObjects.Select((o, i) => { o.SequenceNumber = i; return o; }).ToList(); 

我很惊讶地发现这很有效。