Достижение сложной сортировки через Linq to Objects
Меня попросили применить условную сортировку к набору данных, и я пытаюсь выяснить, как этого добиться с помощью LINQ. В этом конкретном домене заказы на покупку могут быть помечены как первичные или вторичные. Точный механизм, используемый для определения первичного / вторичного статуса, довольно сложен и не имеет отношения к рассматриваемой проблеме.
Рассмотрим данные, приведенные ниже.
Purchase Order Ship Date Shipping Address Total
6 1/16/2006 Tallahassee FL 500.45
19.1 2/25/2006 Milwaukee WI 255.69
5.1 4/11/2006 Chicago IL 199.99
8 5/16/2006 Fresno CA 458.22
19 7/3/2006 Seattle WA 151.55
5 5/1/2006 Avery UT 788.52
5.2 8/22/2006 Rice Lake MO 655.00
Вторичные PO - это те, которые имеют десятичное число, а первичные PO - это целые числа. Требование, с которым я имею дело, предусматривает, что, когда пользователь выбирает сортировку по заданному столбцу, сортировка должна применяться только к первичным PO. Вторичные PO игнорируются для целей сортировки, но все равно должны быть перечислены ниже их первичного PO в порядке убывания даты отгрузки.
Например, скажем, пользователь сортирует по адресу доставки по возрастанию. Данные будут отсортированы следующим образом. Обратите внимание, что если вы игнорируете вторичные PO, данные сортируются по возрастанию адреса (Avery, Фресно, Сиэтл, Таллахасси)
Purchase Order Ship Date Shipping Address Total
5 5/1/2006 Avery UT 788.52
--5.2 8/22/2006 Rice Lake MO 655.00
--5.1 4/11/2006 Chicago IL 199.99
8 5/16/2006 Fresno CA 458.22
19 7/3/2006 Seattle WA 151.55
--19.1 2/25/2006 Milwaukee WI 255.69
6 1/16/2006 Tallahassee FL 500.45
Есть ли способ добиться желаемого эффекта с помощью метода расширения OrderBy? Или я застрял (лучше) применить сортировку к двум наборам данных независимо, а затем слить в один результирующий набор?
public IList<PurchaseOrder> ApplySort(bool sortAsc)
{
var primary = purchaseOrders.Where(po => po.IsPrimary)
.OrderBy(po => po.ShippingAddress).ToList();
var secondary = purchaseOrders.Where(po => !po.IsPrimary)
.OrderByDescending(po => po.ShipDate).ToList();
//merge 2 lists somehow so that secondary POs are inserted after their primary
}
2 ответа
Решение вашей проблемы GroupBy
,
Сначала упорядочите ваш объект согласно выбранному столбцу:
var ordered = purchaseOrders.OrderBy(po => po.ShippingAddress);
Чем вам нужно сгруппировать ваши заказы в соответствии с первичным заказом. Я предположил, что заказ является строкой, поэтому я создал строку IEqualityComparer
вот так:
class OrderComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
x = x.Contains('.') ? x.Substring(0, x.IndexOf('.')) : x;
y = y.Contains('.') ? y.Substring(0, y.IndexOf('.')) : y;
return x.Equals(y);
}
public int GetHashCode(string obj)
{
return obj.Contains('.') ? obj.Substring(0, obj.IndexOf('.')).GetHashCode() : obj.GetHashCode();
}
}
и использовать его для группировки заказов:
var grouped = ordered.GroupBy(po => po.Order, new OrderComparer());
В результате получается древовидная структура, упорядоченная по столбцу ShippingAddress и сгруппированная по первичному идентификатору заказа.
Вы видели методы ThenBy и ThenByDescending?
purchaseOrders.Where(po => po.IsPrimary).OrderBy(po => po.ShippingAddress).ThenByDescending(x=>x.ShipDate).ToList();
Я не уверен, что это будет соответствовать вашим потребностям, потому что я не совсем понимаю, как должен выглядеть окончательный список (po.IsPrimary и! Po.IsPrimary сбивают меня с толку).