方向取决于数据时的OrderByWithDirection



在这篇SO文章中:LINQ中的升序/降序-可以通过参数更改顺序吗?给出了如何按升序或降序进行有条件排序的解决方案。

这篇文章没有涵盖的是,如果我想根据查询中的数据做出决定(实际上,最有可能的是什么),该怎么办?

我似乎做不到:

source.OrderByWithDirection(o => o.MyColumnToOrderBy, o => o.SortingDirection)

那么我需要重写这些方法吗?怎样

-更新-

根据原理,以下是我想要实现的目标:

Strike  Type Price
98      Ask  101
98      Ask  100
98      Ask  99
98      Bid  95
98      Bid  96
98      Bid  97

正如您所看到的,请求是按顺序排列的,但出价是按顺序排序的,这样差异最大的行彼此相邻。所以我想说的是:

source.OrderBy(o => new { o.Strike, o.Type })
  .ThenByWithDirection(o => o.Price, o => o.Type == "Ask" ? __down__ : __up__)

-更新II-

要做到这一点,一种笨拙的方法是发出两个单独的查询,如下所示:

source
  .Where(o => o.Type == "Ask")
  .OrderBy(o => new { o.Strike, o.Type })
  .ThenBy(o => o.Price)
source
  .Where(o => o.Type == "Bid")
  .OrderBy(o => new { o.Strike, o.Type })
  .ThenByDescending(o => o.Price)

并将它们连接到

我没有你的实体/对象,但你能不能不只是做一些类似的事情:

var items = from t in source
    select new { a = t, b = t.Type == "Ask" ? -t.Price : t.Price };
var sorted = from x in items
     orderby x.a.Type, x.b
     select x.a;

也就是说,创建一个包含单个属性的新对象,可以通过该属性执行排序,然后在排序操作中使用该属性?

我为此编写了一个通用扩展方法:

public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> entities, string sortExpression)
        {
            bool descending = sortExpression.ToLowerInvariant().Trim().EndsWith("desc");
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            // sort properties by name
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (sortExpression.Split(' ')[0] == propertyInfo.Name)
                {
                    PropertyInfo info = propertyInfo;
                    if (descending)
                        return entities.OrderByDescending(c => info.GetValue(c, null));
                    else
                        return entities.OrderBy(c => info.GetValue(c, null));
                }
            }
            return entities;
        }

用法:

IEnumerable x = cars.OrderByString("color desc");

希望能有所帮助。

Daniel

一种方法是将信息提取到更有意义的排序结构中:

source
    .Select(o => new {
        o.Strike,
        o.Type,
        o.Price,
        o.AskPrice = o.Type == "Ask" ? o.Price : (int)null,
        o.BidPrice = o.Type == "Bid" ? o.Price : (int)null
    })
    .OrderBy(o => o.Strike)
    .ThenBy(o => o.Type)
    .ThenByDescending(o => o.AskPrice)
    .ThenBy(o => o.BidPrice)

这假设你知道这是你想要排序的两件事

另一种选择是反转其中一个值(例如,出于排序目的,使用1000000-AskPrice,然后可以升序排序)。

IComparer的答案很接近,但需要这样:

public class BidComparer : IComparer<BidDatum> {
    public int Compare(BidDatum x, BidDatum y) {
        return (x.Type != y.Type) ? (x.Type.CompareTo(y.Type)) : ((x.Type == "Ask") ? y.Price.CompareTo(x.Price) : x.Price.CompareTo(y.Price));
    }
}

现在你的Linq可以是这样的:

var ans = srcData.OrderBy(d => d.Strike).ThenBy(d => d, new BidComparer());

我跳过了一个.ThenBy(d => d.Type),因为自定义IComparer也会在出价前对Ask进行排序。

您可以尝试自定义IComparer:

public class MyComparer<T> : IComparer<T> {
   public MyComparer(bool ascending){
      Descending = !ascending;
   }
   public bool Descending {get;set;}
   public int Compare(T x, T y){
      //your normal logic
      int result = ....;
      return Descending ? -result : result;
   }
}

然后在您的OrderBy查询中使用它:

source.OrderBy(o=>o.MyColumnToOrderBy, new MyComparer(true));//true for ascending and false for descending

更新

您可以使用一些enum而不是bool来指示排序方向:

public class MyComparer<T> : IComparer<T> {
   public MyComparer(SortingDirection sortDir){
      Direction = sortDir;
   }
   public SortingDirection Direction {get;set;}
   public int Compare(T x, T y){
      //your normal logic
      int result = ....;
      return Direction == SortingDirection.Descending ? -result : result;
   }
   public enum SortingDirection {
     Ascending,
     Descending
   }
}
//o.SortingDirection should be type of enum SortingDirection
source.OrderBy(o=>o.MyColumnToOrderBy, new MyComparer(o.SortingDirection));

围绕的另一项工作

我认为你可以用GroupBy的一个小技巧来通过o.SortingDirection订购,比如:

source.GroupBy(x=>x.MyColumnToOrderBy)
      .SelectMany(g=> o.SortingDirection == SortingDirection.Ascending ? 
                                            g.OrderBy(a=>a.Key) :
                                            g.OrderByDescending(a=>a.Key));

我认为通常情况下,您将很难实现您提出的OrderByWithDirection。例如,数据集{1, true}, {2, false}, {3, true}, {4, false}的结果会是什么?在你的情况下,它有效的唯一原因是你的第二种排序与第一种排序有很高的相关性,即第二种分类永远不需要比较"出价"one_answers"要价"。

最好的方法是使用一个自定义的IComparator来实现整个排序

int Compare(Entry a, Entry b)
{
    if (a.Type == b.Type)
    {
        // same type, look at the price difference and reverse if they are both Bids
        return a.Price.CompareTo(b.Price) * (a.Type == "Bid" ? -1 : 1);
    }
    else
    {
        // different types, Ask comes first
        return (a.Type == "Ask") ? -1 : 1;
    }
}

相关内容

  • 没有找到相关文章

最新更新