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

时间:2015-06-25 17:47:12

标签: c# .net

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

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>:

,我无法获得正确的结果
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那样将结果链接起来,如何实现它。

1 个答案:

答案 0 :(得分:2)

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

您可以使用它来获取您拥有的所有比较器并创建一个比较器,您可以将其传递给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的方法可以重写为只迭代源序列一次,而不是三次,并且还避免了大量重复:

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]));
}