【问题标题】:Ordering column values with LINQ ignoring empty string values [duplicate]使用LINQ排序列值忽略空字符串值[重复]
【发布时间】:2018-01-12 03:41:14
【问题描述】:

如何使用 LINQ 忽略空字符串值对列值进行排序?

现有的订购代码

datatable.Select().OrderBy(u => u["ColName"]).ToArray();

使用上面的代码,首先列出的空字符串值,然后是有序列表。 但是,我想忽略空字符串值以将它们保持在相同的位置。

【问题讨论】:

  • 保持不变是什么意思? ["", "b","","c","a",""] 应该变成["","a","","b","c",""]
  • 最简单的方法是检查OrderBy子句OrderBy(e => !String.IsNullOrEmpty(u["ColName"])中的空值或空值
  • @SergeyBerezovskiy,没错。
  • 提取所有空字符串的位置,排序,然后重新插入。自定义比较可能会起作用,但这只是巧合,因为无法以这种方式定义满足传递性规则的自定义比较。
  • 我正在将数据表内容导出到 excel,因为我们之间有空行。我们需要将数据表中看到的空行显示在 excel 中。

标签: c# asp.net .net linq c#-4.0


【解决方案1】:

试试

var query = datatable.AsEnumerable();  // Or datatable.Select();

var sorted = query 
             .Where(u => (string) u["ColName"] != "")
             .OrderBy(u => u["ColName"]).ToArray();
var idx = 0;
var results = query 
              .Select(u => (string) u["ColName"] == "" ? u : sorted[idx++]);

【讨论】:

  • 我已经更新了我的答案..
  • 谢谢。它按预期工作正常。
【解决方案2】:

试试这个

datatable.Select().OrderBy(u => !String.IsNullOrEmpty(u["ColName"]).ToArray();

【讨论】:

  • 不会保留空值行的位置
【解决方案3】:

如果是刺列 - datatable.Select().Where(u => !string.IsNullOrEmpty(u["ColName"]) ).OrderBy(u => u["ColName"]).ToArray();

【讨论】:

  • 错误消息说“string.IsNullOrEmpty 的最佳重载方法有一些无效参数”
  • 我相信这将返回一个没有空值的列表。根据 cmets OP 想要包含的空值。
  • @JohnStephen - 那是因为u["ColName"] 是一个对象。 IsNullOrEmpty 需要 string。您必须调用as stringToString() 或以其他方式将其设为字符串。但请注意它是否为空。
  • 问题是你需要调用 u["ColNAme"].ToString(),因为 string.IsNullOrEmpty 需要字符串而不是对象。
【解决方案4】:

提取不含空值的数组:{ "", "2", "", "1", "4", "3" } -> { "2", "1", "4", "3" }

val toOrder = datatable.Select().Where(u => u["ColName"] != "");

排序这个:{ "2", "1", "4", "3" } -> { "1", "2", "3", "4" }

val ordered = toOrder.OrderBy(u => u["ColName"]);

插入旧列表:{ "1", "2", "3", "4" } -> { "", "1", "", "2", "3", "4" }

val newArray = datatable.Select();
int orderedIndex = 0;
for(int i = 0; i < newArray.Count; i++)
{
    if (newArray[i]["ColName"] != "")
    {
        newArray[i] = ordered[orderedIndex++];
    }
}

不是 100% LINQ,但它应该可以工作

【讨论】:

    【解决方案5】:

    您可以编写自己的(扩展)方法来执行此类排序(为简单起见,它用于 DataRows 序列,但您可以使用相同的方法创建通用版本):

    public static IEnumerable<DataRow> SortByNonEmpty(
          this IEnumerable<DataRow> source, string columnName)
    {
        var query = from r in source
                    let value = r.Field<string>(columnName)
                    where !String.IsNullOrEmpty(value)
                    orderby value
                    select r;
    
        using (var ordinalEnumerator = source.GetEnumerator())
        using (var sortedEnumerator = query.GetEnumerator())
        {
            while (ordinalEnumerator.MoveNext())
            {
               if (String.IsNullOrEmpty((ordinalEnumerator.Current.Field<string>(columnName))))
                   yield return ordinalEnumerator.Current;
    
               sortedEnumerator.MoveNext();
               yield return sortedEnumerator.Current;
            }
        }
    }
    

    它使用两个枚举器 - ordinalEnumerator 以原始顺序枚举序列,sortedEnumerator 枚举列中具有非空值的排序序列。 IE。如果您将原始值视为["", "b","","c","a",""],那么第一个枚举器将按原始顺序枚举所有元素。第二个枚举器将只产生元素["a","b","c"]

    然后我们只检查源序列中的每个项目。如果它在列中有空值,那么我们只返回该行(从而保留空值的顺序)。否则,我们从有序序列中取出下一个项目。因此,非空值将按排序顺序排列。

    用法:

    datatable.AsEnumerable().SortByNonEmpty("ColName")
    

    测试

    DataTable table = new DataTable();
    table.Columns.Add("Id", typeof(int));
    table.Columns.Add("Name", typeof(string));
    
    table.Rows.Add(1, "");
    table.Rows.Add(2, "b");
    table.Rows.Add(3, "");
    table.Rows.Add(4, "c");
    table.Rows.Add(5, "a");
    table.Rows.Add(6, "");
    
    table.AsEnumerable().SortByNonEmpty("Name")
    

    输出

    [
      { "Id": 1, "Name": "" },
      { "Id": 5, "Name": "a" },
      { "Id": 3, "Name": "" },
      { "Id": 2, "Name": "b" },
      { "Id": 4, "Name": "c" },
      { "Id": 6, "Name": "" }
    ]   
    

    【讨论】:

      【解决方案6】:
      //On input  { "", "a", "", "c", "f", "b", "", "e", "d" }
      //On output { "", "a", "", "b", "c", "d", "", "e", "f" }
      public static List<string> Sort(List<string> l)
      {
          var filtered = l
              .Select((s, i) => new { i, s })
              .Where(o => !string.IsNullOrEmpty(o.s))
              .OrderBy(o => o.s)
              .ToArray();
      
          var indexed = filtered
              .Select(o => o.i)
              .OrderBy(i => i)
              .Select((n, i) => new { n, filtered[i].s })
              .ToArray();
      
          return l
              .Select((s, i) =>
              {
                  if (string.IsNullOrEmpty(s))
                      return s;
                  return indexed.First(o => o.n == i).s;
              })
              .ToList();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-02
        • 2014-01-20
        • 1970-01-01
        • 2016-03-05
        • 2015-11-15
        • 1970-01-01
        • 2014-11-28
        • 2016-04-29
        相关资源
        最近更新 更多