Подтвердить что ты не робот

LINQ: Добавить столбец столбца столбца

Как можно изменить запрос ниже, чтобы включить столбец для номера строки (т.е. один индекс результатов)?

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

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

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

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

4b9b3361

Ответ 1

Используйте синтаксис метода, в котором 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.

EDIT: Я ищу, чтобы результаты были {idx, col1, col2... col-n} not {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 });

Ответ 2

Используйте этот метод 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;

Ответ 3

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

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

Ответ 4

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

Это задано несколько раз: Как добавить поле индекса к результатам Linq

Ответ 5

как насчет?

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

Ответ 6

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

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

Это безумие, но оно работает.

Ответ 7

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

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

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

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