2013-02-19 5 views
18

Как можно изменить следующий запрос, чтобы включить столбец для номера строки (т. Е. Индекс результатов на основе одного)?LINQ: Добавить колонку столбца

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

EDIT1: Я ищу, что результаты будут {idx, col1, col2...col-n} не {idx, row}.

EDIT2: Номер строки должен соответствовать строкам результата, а не строкам таблицы.

EDIT3: I DataBind Эти результаты представлены на GridView. Моя цель состояла в том, чтобы добавить столбец номера строки в GridView. Возможно, другой подход будет лучше.

+1

Возможный дубликат [Как добавить индексное поле к результатам Linq] (http://stackoverflow.com/questions/269058/how-do-you-add-an-index-field-to-linq-results) – sloth

+0

Вы хотите индекс строки в таблице или индекс отфильтрованного результата? –

+0

Возможный дубликат [добавления индекса к результату запроса linq] (http://stackoverflow.com/questions/4999365/adding-index-to-linq-query-result) – sloth

ответ

25

Используйте метод-синтаксис, где Enumerable.Select имеет перегрузку с индексом:

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

Обратите внимание, что этот подход предполагает, что вы хотите оригинальный индекс строки в таблице, а не в отфильтрованный результат, так как я выбираю индекс до фильтра i с Where.

EDIT: Я ищу результатов быть {IDX, col1, col2 ... кол-п} не {IDX, строка}. Номер строки должен соответствовать строкам результата, а не строк таблицы.

Затем выберите анонимный тип со всеми столбцами, которые необходимо:

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

Я ищу решение, которое разделяет currRow. (см. главную статью) – Steven

+0

@Steven: Отредактировал мой ответ. Вы можете использовать анонимный тип. –

+0

@Steven: вы можете привязать этот результат к GridView. Какая у вас проблема? –

4

Используйте этот метод Select:

Проекты каждый элемент последовательности в новую форму, добавляя индекс элемента.

Пример:

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

В ответ на ваши изменения:

Если вы хотите DataTable как результат, вы можете пройти путь без Linq, просто используя DataView и после этого добавьте дополнительный столбец.

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; 
+0

Предполагается, что OP хочет индекс строк после фильтра , а не индекс строки в таблице. –

1

о чем?

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

Вы пробовали то же самое? –

3

Просто для удовольствия, вот альтернатива Select с двумя аргументами:

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

+1 Да, действительно весело. – sloth

+0

@Steven: Как вы собираетесь использовать эти новые результаты? У вас есть тип с соответствующей структурой? – Jon

+0

Я передам результаты в GridView. Я пытаюсь добавить столбец номера строки в GridView. – Steven

2

Согласно редактированием 1. НЕТ, ВЫ НЕ МОЖЕТЕ Linq возвращает таблицу, как это. Вы можете создавать каждый столбец, но вы теряете силу отображаемых объектов.

Это был предложен несколько раз, прежде чем: How do you add an index field to Linq results

1

Там нет простого способа, если хочет сохранить плоский список столбцов (т.е.OP Edit2), а также хотите, чтобы общее решение работало с любым IEnumerable, не требуя, чтобы вы отображали список ожидаемых столбцов.

Однако существует окольный путь к тому, чтобы просмотреть данные запроса в DataTable с помощью метода ToDataTable() от here, а затем добавить столбец 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 мс для обработки.

Если ваш первоначальный запрос возвратил анонимный тип, тогда определение этого типа будет потеряно при преобразовании, поэтому вы потеряете статическую типизацию имен столбцов результирующего IEnumerable при вызове таблицы. AsEnumerable(). Другими словами, вместо того, чтобы писать что-то вроде table.AsEnumerable(). First() .RowNum вам нужно написать таблицу.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); 

Это добавило около 120 мс к времени обработки для моего набора данных 6500 элементов.

Это сумасшедший, но он работает.

0

Я знаю, что опаздываю на вечеринку, но я хотел показать, что сработало для меня.

У меня есть список объектов, и у объекта есть целое свойство на нем для «номера строки» ... или в этом случае «Sequence Number». Это то, что я сделал, чтобы заполнить это поле:

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

Я был удивлен, увидев, что это сработало.

Смежные вопросы