通过Linq到Objects实现复杂的排序

时间:2009-11-16 15:34:22

标签: linq sorting merge linq-group

我被要求对数据集应用条件排序,我试图弄清楚如何通过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,Fresno,Seattle,Tallahassee)

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 个答案:

答案 0 :(得分:3)

您是否看过ThenBy和ThenByDescending方法?

purchaseOrders.Where(po => po.IsPrimary).OrderBy(po => po.ShippingAddress).ThenByDescending(x=>x.ShipDate).ToList();

我不确定这是否符合您的需求,因为我不太清楚最终列表应该是什么样的(po.IsPrimary和!po.IsPrimary让我感到困惑)。

答案 1 :(得分: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列排序,并按主要订单ID分组。

相关问题