【问题标题】:Order by multiple properties按多个属性排序
【发布时间】:2018-04-12 09:16:32
【问题描述】:

我有想要这样订购的清单

  • 首先是“ab”
  • 然后按“ab”在列表中的字母顺序
  • 然后通过“cd”
  • 然后按“cd”列表中的字母顺序
  • 然后按“ef”
  • 然后按“ef”列表中的字母顺序

其余的按字母顺序排列

我有这个 linq 查询

var groups =  profileModel.Groups.
OrderByDescending(i => i.FullName.ToLower().Contains("ab")).
ThenByDescending(i => i.FullName.ToLower().Contains("cd")).
ThenByDescending(i => i.FullName.ToLower().Contains("ef"));

我应该如何扩展这个?我必须使用分组依据吗?

【问题讨论】:

  • 您注意到您有多个First by?提供样品
  • 你是在 IQueriable(EF to SQL) 上还是在内存 IEnumerable 上这样做
  • 那么“abcdef”的全名怎么样?
  • 注:“then by”的意思是“then another sort”;它不是在谈论垂直分区;您是在尝试描述垂直分区吗?您可以通过多种方式实现,但这...非常奇怪

标签: c# linq


【解决方案1】:

看来你想要这个,那就不用GroupBy

var groupOrders = new List<string> { "ab", "cd", "ef" };

var resultList = profileModel.Groups
    .Select(x => new { ModelGroup = x, First2Letter = x.FullName.Substring(Math.Min(2, x.FullName.Length)) })
    .Select(x => new
    {
        x.ModelGroup,
        x.First2Letter,
        Index = groupOrders.FindIndex(s => s.Equals(x.First2Letter, StringComparison.OrdinalIgnoreCase))
    })
    .OrderByDescending(x => x.Index >= 0) // first all known groups
    .ThenBy(x => x.Index)
    .ThenBy(x => x.ModelGroup.FullName)
    .Select(x => x.ModelGroup)
    .ToList();

【讨论】:

  • 也许将 Equals 替换为 Contains ?
  • @Florian: 不,s 是列表中的字符串,First2Letter 是每个 FullName 的前两个字母。
  • 对,你的解决方案和我想的不一样,我的错!
【解决方案2】:

对于自定义排序,您可以为每个比较条件分配一个值,OrderByDescending 将按此排序。像这样的..

            lstModel = profileModel.Groups.OrderByDescending(m => m.FullName.ToLower().Contains("ab") ? 3 :
            m.FullName.ToLower().Contains("cd") ? 2 :
            m.FullName.ToLower().Contains("ef") ? 1 : 0).ToList();

【讨论】:

    【解决方案3】:

    如果我正确地解决了问题,这将根据物品包含的内容对物品进行排序。应该也可以在 EF 中工作。

    var orderItems = from item in profileModel.Groups
                     let name = item.FullName.ToLower()
                     orderby (name.Contains("ab") ? 1 : 0) + (name.Contains("cd") ? 0.1 : 0) + (name.Contains("ef") ? 0.01 : 0) descending
                     select item;
    

    编辑 重新阅读问题后,这可能是正确的解决方案

    var orderItems = from item in profileModel.Groups
                     let name = item.FullName.ToLower()
                     let order = name.Contains("ab") ? 3 : name.Contains("cd") ? 2 : name.Contains("ef") ? 1 : 0
                     orderby order descending, item.FullName
                     select item;
    

    【讨论】:

      【解决方案4】:

      如果您可能需要测试更多或不同的 level1 值,您可能需要一个通用版本。

      使用方便的扩展方法FirstOrDefault,它采用默认值返回

      public static T FirstOrDefault<T>(this IEnumerable<T> src, Func<T, bool> test, T defval) => src.Where(aT => test(aT)).DefaultIfEmpty(defval).First();
      

      您可以按顺序创建一个由第一级值组成的数组,然后首先对其进行排序,然后按字母顺序:

      var level1 = new[] { "ab", "cd", "ef" };
      
      var ans = groups.OrderBy(i => level1.Select((op, n) => (op, n))
                                          .FirstOrDefault(opn => i.FullName.Contains(opn.op),
                                                          (op: String.Empty, n: level1.Length)).n)
                      .ThenBy(i => i.FullName);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-24
        • 2016-01-06
        • 2012-02-22
        • 2015-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多