繁体   English   中英

使用IComparer而不是OrderBy对字典进行排序

[英]Sort List of Dictionary using IComparer instead of OrderBy

以下是我的收藏以及数据:

var data = new List<Dictionary<object, object>>();
       data.Add(new Dictionary<object, object>() {
                    { "Firstname", "Bob"},
                    { "Middlename", "Ack"},
                    { "Lastname", "Banana"}
       });
       data.Add(new Dictionary<object, object>() {
                    { "Firstname", "Amy"},
                    { "Middlename", "Beck"},
                    { "Lastname", "Apple"}
       });
       data.Add(new Dictionary<object, object>() {
                    { "Firstname", "Charlie"},
                    { "Middlename", "Emy"},
                    { "Lastname", "Coconut"}
       });
       data.Add(new Dictionary<object, object>() {
                    { "Firstname", "Andy"},
                    { "Middlename", "Sob"},
                    { "Lastname", "Apple"}
       });

我想使用以下OrderClause类集合对其进行排序:

List<OrderClause> orderClauseList = new List<OrderClause>()
       {            
            new OrderClause(){ColumnName = "Lastname", IsAscending = false},
            new OrderClause(){ColumnName = "Middlename", IsAscending = true},
            new OrderClause(){ColumnName = "Firstname", IsAscending = true}         
       };

public class OrderClause
    {
        public string ColumnName { get; set; }
        public bool IsAscending { get; set; }
    }

预期结果(字典在最终结果中的顺序)

Firstname: Charlie ,  Middlename: Emy , Lastname: Coconut 
Firstname: Bob, Middlename: Ack, Lastname: Banana 
Firstname: Amy, Middlename: Beck, Lastname: Apple
Firstname: Andy, Middlename: Sob, Lastname: Apple

以下使用OrderBy扩展方法可以完成此工作:

  public static List<Dictionary<object, object>> Sort(this  
  List<Dictionary<object, object>> data, List<OrderClause> orderClauseList)
 {
    // If OrderBy collection is empty, then return original collection       
    if (orderClauseList == null || !orderClauseList.Any())
        return data;

    // First one is OrderBy or OrderByDescending.
    var orderClauseFirst = orderClauseList.First();
    IOrderedEnumerable<Dictionary<object, object>> ordered = (orderClauseFirst.IsAscending)
                                                             ? data.OrderBy(d => d[orderClauseFirst.ColumnName])
                                                             : data.OrderByDescending(d => d[orderClauseFirst.ColumnName]);

    // Second element onwards it is thenBy or ThenByDescending
    ordered = orderClauseList.Skip(1) // Skip first element as its already processed
              .Aggregate(ordered, (current, orderClause) => 
                                        (orderClause.IsAscending) 
                                        ? current.ThenBy(d => d[orderClause.ColumnName]) 
                                        : current.ThenByDescending(d => d[orderClause.ColumnName]));

    return ordered.ToList();
}

但是,使用以下IComparer<T>:不能达到正确的结果IComparer<T>:

class NameSorter : IComparer<Dictionary<object, object>>
{     
    public OrderClause OC { get; set;}  

    public int Compare( Dictionary<object, object> x, Dictionary<object, object> y )
    {
        int retVal = 0;

       if(OC.IsAscending)
        retVal = string.Compare(x[OC.ColumnName].ToString(),y[OC.ColumnName].ToString());
       else 
        retVal = string.Compare(y[OC.ColumnName].ToString(),x[OC.ColumnName].ToString());

        return retVal;
    }
}

以下是IComparer<T>代码的用法:

foreach(OrderClause oc in orderClauseList)
       {       
          NameSorter nSorter = new NameSorter();
          nSorter.OC = oc;
          data.Sort(nSorter);
       }  

IComparer代码无法像OrderBy一样完成如何链接结果的方法。

这是可用于链接比较器的类。 它将接受比较器序列,然后依次比较使用每个比较器的每个项目,并返回第一个非零比较的值;如果它们全为零,则返回零。

您可以使用它来获取您拥有的所有比较器,并创建一个比较器,您可以将其传递给对Sort的单个调用或您需要使用单个比较器的任何对象。

public class ComparerChain<T> : IComparer<T>
{
    private IEnumerable<IComparer<T>> comparers;
    public ComparerChain(IEnumerable<IComparer<T>> comparers)
    {
        this.comparers = comparers;
    }

    public int Compare(T x, T y)
    {
        return comparers.Select(comparer => comparer.Compare(x, y))
            .FirstOrDefault(result => result != 0);
    }
}

OrderBy一句,您的基于OrderBy的方法可以重写为只重复一次源序列(而不是三次),并且还避免了很多重复:

public static IEnumerable<Dictionary<object, object>> Sort(
    this IEnumerable<Dictionary<object, object>> data,
    IEnumerable<OrderClause> orderClauseList)
{
    var ordered = data.OrderBy(_ => 1);
    return orderClauseList.Aggregate(ordered, (current, orderClause) =>
        (orderClause.IsAscending)
        ? current.ThenBy(d => d[orderClause.ColumnName])
        : current.ThenByDescending(d => d[orderClause.ColumnName]));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM