C# LINQ:添加 RowNumber 列

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14960563/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:33:27  来源:igfitidea点击:

LINQ: Add RowNumber Column

c#.netlinq

提问by Steven

How can the query below be modified to include a column for row number (ie: one-based index of results)?

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

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

EDIT1: I'm looking for the results to be {idx, col1, col2...col-n}not {idx, row}.

EDIT1:我正在寻找结果{idx, col1, col2...col-n}not {idx, row}

EDIT2: The row number should correspond to result rows not the table rows.

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

EDIT3: I DataBindthese results to a GridView. My goal was to add a row number column to the GridView. Perhaps a different approach would be better.

EDIT3:我将DataBind这些结果转换为GridView. 我的目标是在GridView. 也许不同的方法会更好。

采纳答案by Tim Schmelter

Use the method-syntax where Enumerable.Selecthas an overload with the index:

使用Enumerable.Select具有索引重载的方法语法:

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

Note that this approach presumes that you want the original index of the row in the table and not in the filtered result since i select the index before i filter with Where.

请注意,此方法假定您想要表中行的原始索引而不是过滤结果中的原始索引,因为我在使用Where.

EDIT: I'm looking for the results to be {idx, col1, col2...col-n} not {idx, row}. The row number should correspond to result rows not the table rows.

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

Then select the anonymous type with all columns you need:

然后选择您需要的所有列的匿名类型:

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 });

回答by sloth

Use this Selectmethod:

使用这个Select方法:

Projects each element of a sequence into a new form by incorporating the element's index.

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

Example:

例子:

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


In response to your edit:

回应您的编辑:

If you want a DataTableas result, you can go the non-Linq way by simply using a DataViewand add a additional column afterwards.

如果您想要一个DataTable结果,您可以通过简单地使用 aDataView并在之后添加一个附加列来采用非 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;

回答by Carlos Martinez T

what about?

关于什么?

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

回答by Jon

Just for fun, here's an alternative to Selectwith two arguments:

只是为了好玩,这里Select有两个参数的替代方案:

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

回答by Carlos Martinez T

According to you edit 1. NO, YOU CAN'TLinq returns the table as it is. You can build each column, but you lose the power of mapped entities.

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

This has been asked multiple times before: How do you add an index field to Linq results

之前已经多次问过这个问题: How do you add an index field to Linq results

回答by ivanatpr

There is no straightforward way if want to keep a flat list of columns (i.e. OP's Edit2) and also want a generic solution that works with any IEnumerable without requiring you to list out the set of expected columns.

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

However, there is a roundabout way to kinda go about it which is to dump the query results into a DataTable using the ToDataTable() method from hereand then add a RowNumber column to that table.

但是,有一种迂回的方法可以解决它,即使用此处的 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;

This would likely cause performance issues with large datasets but it's not insanely slow either. On my machine a dataset with ~6500 rows took 33ms to process.

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

If your original query returned an anonymous type, then that type definition will get lost in the conversion so you'll lose the static typing on the column names of the resulting IEnumerable when you call table.AsEnumerable(). In other words, instead of being able to write something like table.AsEnumerable().First().RowNum you instead have to write table.AsEnumerable().First()["RowNum"]

如果您的原始查询返回匿名类型,那么该类型定义将在转换中丢失,因此当您调用 table.AsEnumerable() 时,您将丢失生成的 IEnumerable 列名的静态类型。换句话说,你必须写 table.AsEnumerable().First()["RowNum"] 而不是像 table.AsEnumerable().First().RowNum 这样的东西

However, if you don't care about performance and really want your static typing back, then you can use JSON.NET to convert the DataTable to a json string and then back to a list based on the anonymous type from the original query result. This method requires a placeholder RowNum field to be present in the original query results.

但是,如果您不关心性能并且真的希望恢复静态类型,那么您可以使用 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);

This added about 120ms to the processing time for my 6500 item dataset.

这使我的 6500 项数据集的处理时间增加了大约 120 毫秒。

It's crazy, but it works.

这很疯狂,但它有效。

回答by Joe

I know I'm late to the party, but I wanted to show what worked for me.

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

I have a list of objects, and the object has an integer property on it for "row number"... or in this case, "Sequence Number". This is what I did to populate that field:

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

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

I was surprised to see that this worked.

我很惊讶地看到这奏效了。

回答by Arun Prasad E S

This one helped me in my case - Excel sheet extraction. anonymous type

在我的情况下,这个帮助了我 - Excel 工作表提取。匿名类型

var UploadItemList = ItemMaster.Worksheet().AsEnumerable().Select((x, index) => new
{
    Code = x["Code"].Value == null ? "" : x["Code"].Value.ToString().Trim(),
    Description = x["Description"].Value == null ? "" : x["Description"].Value.ToString().Trim(),
    Unit = x["Unit"].Value == null ? "" : x["Unit"].Value.ToString().Trim(),
    Quantity = x["Quantity"].Value == null ? "" : x["Quantity"].Value.ToString().Trim(),
    Rate = x["Rate"].Value == null ? "" : x["Rate"].Value.ToString().Trim(),
    Amount = x["Amount"].Value == null ? "" : x["Amount"].Value.ToString().Trim(),
    RowNumber = index+1
}).ToList();

回答by Sense Softech

int Lc = 1;

var Lst = LstItemGrid.GroupBy(item => item.CategoryName)
    .Select(group => new { CategoryName = group.Key, Items = group.ToList() ,RowIndex= Lc++ })
    .ToList();