词典使用的IComparer代替排序依据排序列表词典、依据、列表、IComparer

2023-09-03 06:49:37 作者:那与爱无关″

下面是我收集,以及数据:

Following is my collection, along with data:

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

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

Expected Result (order of Dictionaries in final result)

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

随着使用排序依据扩展方法做这项工作:

Following extension method using OrderBy does the job:

  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&LT; T&GT;

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&LT; T&GT; code:

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

的IComparer code是无法链结果为排序依据为已完成,如何实现它。

IComparer code is not able to chain results as done by OrderBy, how to achieve it.

推荐答案

下面是你可以用它来链comparers类。它将接受comparers的序列,然后进行比较,它使用每个comparers的每个项目中,为了,返回的第一非零比较的值,或零,如果它们都为零。

Here is a class that you can use to chain comparers. It will accept a sequence of comparers and then to compare each item it uses each of the comparers, in order, returning the value of the first non-zero comparison, or zero if they're all zero.

您可以使用此采取一切,你有comparers,创造任何你所需要的单一个比较器,你可以通过一个单一呼叫排序或比较器的。

You can use this to take all of the comparers that you have and create a single comparer that you can pass to a single call to Sort or whatever you need the single comparer for.

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

在一个侧面说明,你的排序依据基础的方法可以被重新写入都只有迭代源序列一次,而是三次,还可以避免很多的复制:

On a side note, your OrderBy based method can be re-written to both only iterate the source sequence once, instead of three times, and also avoid much of the duplication:

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