У меня есть файл CSV с записями, которые необходимо отсортировать, а затем сгруппировать в партии произвольного размера (например, 300 максимальных записей за партию). Каждая партия может иметь менее 300 записей, поскольку содержимое каждой партии должно быть однородным (на основе содержимого пары разных столбцов).Пакет с несколькими группами GroupBy
Мой LINQ заявление, вдохновленный этим ответом на batching with 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
. Я понимаю, почему я получаю ошибку, но в целом я не уверен, как исправить этот запрос. Как это сделать?
UPDATE Я почти достиг того, что я после, со следующим:
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);
}
}
Хитрость здесь в обход выберите «позиции индекса» overlaod, с помощью переменной закрытия (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 };
Теперь он делает то, что я хочу. Мне просто жаль, что мне не нужна эта отдельная функция!
Мой intellisense и компилятор отказывается разрешить мне поместить «группу» после «выбрать новый», если я не переключусь на точечную нотацию. –
«В x» важно. –
Исправлено много неловких опечаток. Теперь я закончил (работает ли это или нет). –