【问题标题】:Custom sort of DataTable where index is needed需要索引的自定义类型的 DataTable
【发布时间】:2019-06-12 11:18:53
【问题描述】:

正如标题所说,我需要对我的 DataTable 进行自定义排序,其中我使用 DataRow 的索引,结果应该是 EnumerableRowCollection 或 OrderedEnumerableRowCollection,因为我想要一个表(默认顺序)和一个 DataView(自定义顺序)。

我想要的顺序:首先按几列排序(例如姓名,姓氏,...)。然后拆分table1和table2中的表格(只是表格的一半)。然后交替从第一个和第二个表中选择。结果应该是

table1 的行
table2 的行
table1的行

原表不应该受到影响,结果应该是对原表的引用。

internal static DataView GetSortedView(this DataTable table)
{
    return table.GetSortedTable().AsDataView();
}

internal static void OrderedEnumerableRowCollection<DataRow> GetSortedTable(this DataTable table)
{

int half = table.Rows.Count / 2;
//sort columns by name for example
var enumerable = table.AsEnumerable().OrderBy(field => field.Field<string>("Name"), new NaturalStringComparer());

//here is the tricky part
enumerable= enumerable.OrderBy(row =>
                    {
                        int myIndex = ?; //I cannot use table.Rows.IndexOf(row) because the order of the current OrderedEnumerableRowCollection should be used and not the default order of the table

                        bool upperHalf = myIndex > half;
                        if (upperHalf)
                        {
                            myIndex -= half;
                        }

                        return new CustomSortItem(myIndex , upperHalf);
                    }, new CustomSort());
return enumerable;
}

我尝试先为索引添加一个新列,但这并没有真正起作用,因为当我尝试删除该列时,最后由于延迟加载而收到异常。

internal static void OrderedEnumerableRowCollection<DataRow> GetSortedTable(this DataTable table)
{

//create another column for an index
string tempSortName = "[TEMP_SORT]";
table.Columns.Add(tempSortName);

//sort columns by Name for example
var enumerable= table.AsEnumerable().OrderBy(field => field.Field<string>("Name"), new NaturalStringComparer());

//set the temporary order (index)
int count = 0;
foreach(DataRow row in enumerable)
{
    row[tempSortName] = count++;
}

//here is the tricky part
int half = table.Rows.Count / 2;
enumerable= enumerable.OrderBy(row =>
                    {
                        int myIndex = int.parse(row[tempSortName].ToString()); //exception here. column not found

                        bool upperHalf = myIndex  > half;
                        if (upperHalf)
                        {
                            myIndex  -= half;
                        }

                        return new CustomSortItem(myIndex , upperHalf);
                    }, new CustomSort());

                    table.Columns.Remove(tempSortName);
return enumerable;
}

我也不想使用 IEnumerable,因为当我创建 DataView 时,我必须创建另一个表才能创建一个,然后引用丢失(view.Table 不是原始表,只是没有参考)。

IEnumerable<DataRow> enumerable...
enumerable.CopyToDataTable().AsDataView();
// I have to call CopyToDataTable() in order to create a DataView

【问题讨论】:

    标签: c# linq datatable


    【解决方案1】:

    如果使用Select的两个参数版本按顺序计算行数呢?

    enumerable = enumerable.Select((r, i) => new { r, i })
                           .OrderBy(ri => {
                                var upperHalf = ri.i > half;
                                var myIndex = ri.i - (upperHalf ? half : 0);
                                return new CustomSortItem(myIndex, upperHalf);
                            }, new CustomSort());
    

    【讨论】:

    • Select 语句返回 IEnumerable&lt;DataRow&gt; 而不是 EnumerableDataRowCollection&lt;DataRow&gt;。使用 IEnumerable 我无法创建引用原始表的视图,但 EnumerableDataRowcollection 可以做到。
    【解决方案2】:

    一段时间后,我找到了解决方案,GetSortedTableGetSortedView 的解决方案不同(每个都有自己的解决方案)。如果有人有更好的解决方案,我将不胜感激。

    internal static void DataView GetSortedView(this DataTable table)
    {
    
       //create another column for an index
       string tempSortName = "[TEMP_SORT]";
       table.Columns.Add(tempSortName);
    
       //sort columns by Name for example
       var enumerable= table.AsEnumerable().OrderBy(field => field.Field<string>("Name"), new NaturalStringComparer());
    
       //set the temporary order (index)
       int count = 0;
       foreach(DataRow row in enumerable)
       {
           row[tempSortName] = count++;
       }
    
       //here is the tricky part
       int half = table.Rows.Count / 2;
       enumerable= enumerable.OrderBy(row =>
        {
    
          if (int.TryParse(row[tempSortName]?.ToString(), out int myIndex )) //everything here is triggered if row[tempSortName] is set... or before it is set... idk... wtf. so there is a new column but there are not any indices in it (or just one)
           {
             myIndex++;
             bool upperHalf = myIndex  > half;
             if (upperHalf)
             {
                myIndex  -= half;
             }
             return new CustomSortItem(myIndex , upperHalf);
           }
        }, new CustomSort());
    
       DataView view = enumerable.AsDataView();
       view.Table.Columns.Remove(tempSortName);
    
       return view;
    }
    
    
    internal static IEnumerable<DataRow> GetSortedTable(this DataTable table)
    {
       IEnumerable<DataRow> result;
       //sort columns by Name for example
       var enumerable= table.AsEnumerable().OrderBy(field => field.Field<string>("Name"), new NaturalStringComparer());
       int half =  table.Rows.Count / 2;
       IEnumerable<DataRow> one = enumerable.Take(half);
       IEnumerable<DataRow> two = enumerable.Skip(half);
       result = one.InterleaveEnumerationsOfEqualLength(two);
       return result;
     }
    
    internal static IEnumerable<DataRow> InterleaveEnumerationsOfEqualLength<DataRow>(this IEnumerable<DataRow> first, IEnumerable<DataRow> second)
    {
       using (IEnumerator<DataRow> enumerator1 = first.GetEnumerator(), enumerator2 = second.GetEnumerator())
       {
          while (enumerator1.MoveNext() && enumerator2.MoveNext())
          {
             yield return enumerator1.Current;
             yield return enumerator2.Current;
          }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      相关资源
      最近更新 更多