[英]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.