1

在这篇 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__)

- 更新二 -

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

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)

并将它们连接起来

4

6 回答 6

1

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

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

希望能帮助到你。

丹尼尔

于 2013-08-21T05:39:25.550 回答
1

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

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;

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

于 2013-08-21T06:18:21.790 回答
1

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

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,然后它可以按升序排序)。

于 2013-08-21T06:30:06.277 回答
1

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 也对出价前的问进行排序。

于 2016-10-17T20:29:20.020 回答
0

您可以尝试自定义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

更新

您可以使用 someenum而不是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));
于 2013-08-21T04:26:47.290 回答
0

我认为总的来说,您将很难实施您提出的OrderByWithDirection. 例如数据集的结果是什么{1, true}, {2, false}, {3, true}, {4, false}?它适用于您的情况的唯一原因是您的第二类与您的第一个具有高度相关性,即第二类永远不需要比较“出价”和“要价”。

解决此问题的最佳方法是使用实​​现整个排序的自定义 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;
    }
}
于 2013-08-21T22:41:49.320 回答