Arhn - архитектура программирования

Пакет с несколькими GroupBy

У меня есть файл CSV с записями, которые необходимо отсортировать, а затем сгруппировать в пакеты произвольного размера (например, 300 максимальных записей в пакете). В каждом пакете может быть менее 300 записей, поскольку содержимое каждого пакета должно быть однородным (на основе содержимого нескольких разных столбцов).

Мое заявление LINQ, вдохновленное этим ответом на пакетная обработка с помощью LINQ выглядит следующим образом:

var query = (from line in EbrRecords
            let EbrData = line.Split('\t')
            let Location = EbrData[7]
            let RepName = EbrData[4]
            let AccountID = EbrData[0]
            orderby Location, RepName, AccountID).
            Select((data, index) => new {
                Record = new EbrRecord(
                AccountID = EbrData[0],
                AccountName = EbrData[1],
                MBSegment = EbrData[2],
                RepName = EbrData[4],
                Location = EbrData[7],
                TsrLocation = EbrData[8]
                )
                ,
                Index = index}
                ).GroupBy(x => new {x.Record.Location, x.Record.RepName, batch = x.Index / 100});    

«/ 100» дает мне произвольный размер ведра. Другие элементы groupby предназначены для достижения однородности между партиями. Я подозреваю, что это почти то, что я хочу, но это дает мне следующую ошибку компилятора: A query body must end with a select clause or a group clause. Я понимаю, почему я получаю сообщение об ошибке, но в целом я не знаю, как исправить этот запрос. Как это сделать?

ОБНОВЛЕНИЕ Я почти добился того, что мне нужно, со следующим:

List<EbrRecord> input = new List<EbrRecord> {
    new EbrRecord {Name = "Brent",Age = 20,ID = "A"},
    new EbrRecord {Name = "Amy",Age = 20,ID = "B"},
    new EbrRecord {Name = "Gabe",Age = 23,ID = "B"},
    new EbrRecord {Name = "Noah",Age = 27,ID = "B"},
    new EbrRecord {Name = "Alex",Age = 27,ID = "B"},
    new EbrRecord {Name = "Stormi",Age = 27,ID = "B"},
    new EbrRecord {Name = "Roger",Age = 27,ID = "B"},
    new EbrRecord {Name = "Jen",Age = 27,ID = "B"},
    new EbrRecord {Name = "Adrian",Age = 28,ID = "B"},
    new EbrRecord {Name = "Cory",Age = 29,ID = "C"},
    new EbrRecord {Name = "Bob",Age = 29,ID = "C"},
    new EbrRecord {Name = "George",Age = 29,ID = "C"},
    };

//look how tiny this query is, and it is very nearly the result I want!!!
int i = 0;
var result = from q in input
                orderby q.Age, q.ID
                group q by new { q.ID, batch = i++ / 3 };

foreach (var agroup in result)
{
    Debug.WriteLine("ID:" + agroup.Key);
    foreach (var record in agroup)
    {
        Debug.WriteLine(" Name:" + record.Name);
    }
}

Хитрость здесь заключается в том, чтобы обойти перекрытие select «index position», используя переменную закрытия (в данном случае int i). Результаты вывода следующие:

ID:{ ID = A, batch = 0 }
 Name:Brent
ID:{ ID = B, batch = 0 }
 Name:Amy
 Name:Gabe
ID:{ ID = B, batch = 1 }
 Name:Noah
 Name:Alex
 Name:Stormi
ID:{ ID = B, batch = 2 }
 Name:Roger
 Name:Jen
 Name:Adrian
ID:{ ID = C, batch = 3 }
 Name:Cory
 Name:Bob
 Name:George

Хотя этот ответ приемлем, он лишь немного меньше идеального результата. Должно быть, чтобы в первом появлении «партии 'B'» было 3 целых числа (Эми, Гейб, Ной), а не два (Эми, Гейб). Это связано с тем, что позиция индекса не сбрасывается при идентификации каждой группы. Кто-нибудь знает, как сбросить мою пользовательскую позицию индекса для каждой группы?

ОБНОВЛЕНИЕ 2 Кажется, я нашел ответ. Во-первых, сделайте дополнительную функцию, подобную этой:

    public static bool BatchGroup(string ID, ref string priorID )
    {
        if (priorID != ID)
        {
            priorID = ID;
            return true;
        }
        return false;
    }

Во-вторых, обновите запрос LINQ следующим образом:

int i = 0;
string priorID = null;
var result = from q in input
                orderby q.Age, q.ID
             group q by new { q.ID, batch = (BatchGroup(q.ID, ref priorID) ? i=0 : ++i) / 3 };

Теперь он делает то, что я хочу. Я просто хочу, чтобы мне не нужна была эта отдельная функция!

02.06.2011

Ответы:


1
orderby Location, RepName, AccountID

После вышеизложенного должно быть предложение select, как показано в ответе StriplingWarrior. Запросы на понимание Linq должны заканчиваться на select или group by.


К сожалению, есть логический дефект... Допустим, у меня есть 50 аккаунтов в первой группе и 100 аккаунтов во второй группе с размером пакета 100. Исходный код выдаст 3 пакета размером 50, а не 2 пакета по 50, 100.

Вот один из способов исправить это.

IEnumerable<IGrouping<int, EbrRecord>> query = ...

  orderby Location, RepName, AccountID
  select new EbrRecord(
    AccountID = EbrData[0],
    AccountName = EbrData[1],
    MBSegment = EbrData[2],
    RepName = EbrData[4],
    Location = EbrData[7],
    TsrLocation = EbrData[8]) into x
  group x by new {Location = x.Location, RepName = x.RepName} into g
  from g2 in g.Select((data, index) => new Record = data, Index = index })
              .GroupBy(y => y.Index/100, y => y.Record)
  select g2;


List<List<EbrRecord>> result = query.Select(g => g.ToList()).ToList();

Также обратите внимание, что использование GroupBy для пакетной обработки выполняется очень медленно из-за избыточных итераций. Вы можете написать цикл for, который сделает это за один проход по упорядоченному набору, и этот цикл будет работать намного быстрее, чем LinqToObjects.

02.06.2011
  • Мой intellisense и компилятор отказываются разрешать мне размещать группу после выбора нового, если я не переключусь на точечную нотацию. 02.06.2011
  • Исправлено множество досадных опечаток. Теперь я закончил (независимо от того, работает это или нет). 02.06.2011
  • Добавлено преобразование списка в список. 02.06.2011
  • Хорошо, после дальнейшего анализа я вижу, что ваш ответ дает именно правильный результат. Я проверил это как ответ. Но, О ЧЕЛОВЕК, это то, что вы сделали занятой запрос!!! Пожалуйста, посмотрите на обновление, которое я сделал для своего вопроса, где я нашел почти идеальное (и гораздо более простое) решение. Если вы сможете заставить мое обновление работать без особых усилий, я также проголосую за него. :) 05.06.2011
  • пожимает плечами вы хотели, чтобы запрос с несколькими группами выполнял пакетную обработку. Я дал тебе один. Теперь вам нужен запрос, использующий информацию о предыдущих строках для пакетной обработки. Это так далеко от первоначального запроса, что это должен быть отдельный вопрос. 05.06.2011

  • 2

    Это работает?

    var query = (from line in EbrRecords
            let EbrData = line.Split('\t')
            let Location = EbrData[7]
            let RepName = EbrData[4]
            let AccountID = EbrData[0]
            orderby Location, RepName, AccountID
            select new EbrRecord(
                    AccountID = EbrData[0],
                    AccountName = EbrData[1],
                    MBSegment = EbrData[2],
                    RepName = EbrData[4],
                    Location = EbrData[7],
                    TsrLocation = EbrData[8])
            ).Select((data, index) => new
            {
                Record = data,
                Index = index
            })
            .GroupBy(x => new {x.Record.Location, x.Record.RepName, batch = x.Index / 100},
                x => x.Record);
    
    02.06.2011
  • Я ожидаю список списков EbrRecord (список списков). Но приведенное выше дает мне список для анонимного типа, который содержит только Location, RepName и пакет. Мне интересно, действительно ли сообщение, на которое я ссылаюсь, делает то, что я думал или надеялся. 02.06.2011
  • @Brent: GroupBy создаст IEnumerable из IGroupings, каждый из которых имеет Key с Location, RepName и партией, но также сам является IEnumerable, содержащим выбранные значения. Если вы используете перегрузку в моем обновленном ответе, у вас должен быть IEnumerable<IEnumerable<EbrRecord>>. Однако я думаю, что вполне вероятно, что это не совсем то, на что вы надеялись. Обязательно прочитайте ответ Дэвида Б. Он делает несколько отличных выводов. 03.06.2011
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..