【问题标题】:Sort rows of DataTable in particular order we want按我们想要的特定顺序对 DataTable 的行进行排序
【发布时间】:2021-04-13 03:27:35
【问题描述】:

假设我有两列的 DataTable

Column1 Column2
abc jan
def dec
cba feb
bdf nov
aaa dec

我有第 2 列的月份列表。 我想按月份排序

输出:

Column1 Column2
def dec
aaa dec
bdf nov
cba feb
abc jan

我尝试了什么:

string[] monthList = { "dec", "nov", "oct", "sep",,,, "feb", "jan"};
DataTable dataExistingTable
DataTable temp = new DataTable();
foreach(string month in monthList)
{
  var filteredData = dataExistingTable.AsEnumerable().Where(x => x["Column2"] == month);
  temp.Merge(filteredData.CopyToDataTable());
}

请建议一些更快/更好的方法!!!

【问题讨论】:

    标签: c# sorting datatable


    【解决方案1】:

    Waqas Raja 的回答帮助我解决了问题并写下了这个答案。

    按您想要的顺序排序的更简单/更快的方法是使用 DataColumn 的 Expression 属性。

    您可以通过多种方式将表达式分配给列

    table.Columns.Add(columnName, type, expression);
    

    table.Columns.Add(columnName, type);
    table.Columns[columnName].Expression = expression;
    

    对于这个问题,我在表达式中使用了 IIF,其作用类似于 If Else 语句
    用法:IIF(condition, 'true statement', 'false statement')

    想知道什么样的条件可以使用https://docs.microsoft.com/en-us/dotnet/api/system.data.datacolumn.expression?view=net-5.0

    下面的方法给出了具有任意数量对象的列表的表达式

      private static string GetColumnExpression(List<object> distinctList, string columnName)
      {
             int counter = 1;
             string expression = "";
             foreach (var item in distinctList)
             {
                 expression += $"IIF ([{columnName}] = '{item}', {counter++}, ";
             }
             expression += "0";
             for (int k = 0; k < distinctList.Count; k++)
             {
                 expression += ")";
             }
    
             return expression;
       }
    

    当您应用条件(如 IIF)超过 90/96 的表达式时,它可能会抛出异常,提示 “表达式太复杂”

    对于对象超过 90/96 的列表,下面的代码会有所帮助!

    private static List<string> GetColumnExpressions(List<string> distinctList, string columnName, string sortingColumn)
                {
                    var list = distinctList;
                    List<string> expressions = new List<string>();
                    int maxLimit = 90, listCount = distinctList.Count, counter = 1, loopCount = 1;
                    while (listCount != 0)
                    {
                        string expression = "";
                        if (loopCount > 1)
                        {
                            expression = $"IIF ([ExtraCol] <> 0, [ExtraCol], ";
                        }
                        int conditionCount = listCount >= maxLimit ? maxLimit : listCount;
                        for (int i = 0; i < conditionCount; i++)
                        {
                            expression += $"IIF ([{columnName}] = '{list[0]}', {counter++}, ";
                            list.RemoveAt(0);
                        }
                        expression += "0";
                        for (int k = 0; k < conditionCount; k++)
                        {
                            expression += ")";
                        }
                        if (loopCount > 1)
                        {
                            expression += ")";
                        }
                        expressions.Add(expression);
                        listCount = list.Count;
                        loopCount++;
                    }
                    return expressions;
                }
    

    用法如下:

    //"MonthNumber" is column Added For Expression/Sorting
                    var expressions = GetColumnExpressions(list, "Column2", "MonthNumber");
                    table.Columns.Add("MonthNumber", typeof(int));
                    string sourceColumn = "MonthNumber", destColumn = "MonthNumber";
                    for (int k = 0; k < expressions.Count; k++)
                    {
                        if (k > 0)
                        {
                            destColumn = "Extra" + k;
                            table.Columns.Add(destColumn, typeof(int));
                            for (int row = 0; row < table.Rows.Count; row++)
                            {
                                table.Rows[row][destColumn] = table.Rows[row][sourceColumn];
                            }
                            expressions[k] = expressions[k].Replace("ExtraCol", sourceColumn);
                            sourceColumn = destColumn;
                        }
                        string expression = expressions[k];
                        table.Columns[destColumn].Expression = expression;
                    }
    

    排序和删除多余的列

      table.DefaultView.Sort = $"{destColumn}";
      for (int k = expressions.Count - 1; k > 0; k--)
      {
          table.Columns.Remove("Extra" + k);
      }
      table.Columns.Remove("MonthNumber");
    
    
    var sortedTable = table.defaultView.ToTable();
    

    【讨论】:

      【解决方案2】:

      在我的应用程序中,我通常使用此算法按特殊顺序对不同项目进行排序。只有 OrderedListItem 通常是 DB 表,Column2 通常是 OrderedListItem 的外键。这样我就不需要第二个查询了。

      public static void Main()
      {
          List<OrderedListItem> orderedList=null;
          List<TableItem> tableItems=null;
          
           PrepareData( ref orderedList, ref tableItems);
           
          var query =
                  (from ti in tableItems
                   join ol in orderedList on ti.Column2 equals ol.Name
                   select new
                   {
                       Column1 = ti.Column1,
                       Column2 = ti.Column2,
                       OrderNum = ol.OrderNum
                   }).OrderBy(i => i.OrderNum)
                  .ToArray();
      
          var result = query.Select(q => new TableItem { Column1 = q.Column1, Column2 = q.Column2 }).ToArray();
          
      }
      
      public static void PrepareData(ref List<OrderedListItem> orderedList, ref List<TableItem> tableItems)
      {
               orderedList = new List<OrderedListItem> {
                  new OrderedListItem ( 1,"Jan",100),
                  new OrderedListItem ( 2,"Feb",200),
                  new OrderedListItem ( 3,"Mar",300),
                  new OrderedListItem  ( 4, "Apr",400)
                  };
      
           tableItems = new List<TableItem> {
           new TableItem  {Column1="cba", Column2="Feb"},
                   new TableItem  {Column1="abc", Column2="Jan"},
                  
          };
      }
      
      
      public class OrderedListItem
      {
          public int Id { get; set; }
          public string Name { get; set; }
          public int OrderNum { get; set; }
          
          public  OrderedListItem(int id, string name, int orderNum)
          {
              
                  Id=id;
                  Name=name;
                  OrderNum=orderNum;
          }
      }
      public class TableItem
      {
              public string Column1 { get; set; }
              public string Column2 { get; set; }
      }
      

      【讨论】:

        【解决方案3】:

        添加基于表达式的列

        dataExistingTable.Columns.Add("MonthNumber", typeof(int),
            "IIF ([Column2] = 'dec', 12, (IIF ([Column2] = 'nov', 11, (IIF ([Column2] = 'oct', 10, (IIF ([Column2] = 'sep', 9, 8)))))))");
        

        然后对基于表达式的列应用排序

        dataExistingTable.DefaultView.Sort = "MonthNumber desc";
        

        然后表格的 DefaultView 会给你排序的行。

        // dataExistingTable.DefaultView;
        

        【讨论】:

        • 感谢您的回答。如果列表包含 100 个字符串而不是月份怎么办
        • 目前您需要为每个字符串从 12 到 1 的权重。但是,您也可以对字符串或日期或其他数据类型列应用排序
        猜你喜欢
        • 2016-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-24
        • 2020-11-05
        • 1970-01-01
        相关资源
        最近更新 更多