У меня есть 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" дает мне произвольный размер корзины. Другие элементы группы предназначены для достижения однородности между партиями. Я подозреваю, что это почти то, что я хочу, но это дает мне следующую ошибку компилятора: 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);
}
}
Хитрость в том, чтобы обойти выбранную «позицию индекса» с помощью закрывающей переменной (в данном случае 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 };
Теперь он делает то, что я хочу. Я просто хотел бы, чтобы мне не нужна эта отдельная функция!