2012-02-10 2 views
0

Я использую это ниже:Как Concat только уникальные столбцы с данными

public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2) 
    { 
     using (DataTable targetTable = dt1.Clone()) 
     { 
      var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc => 
       new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
        dc.ColumnMapping)); 
      var dt2FilterQuery = from dc in dt2Query.AsEnumerable() 
           where targetTable.Columns 
             .Contains(dc.ColumnName) == false 
           select dc; 
      targetTable.Columns.AddRange(dt2FilterQuery.ToArray()); 
      var rowData = from row1 in dt1.AsEnumerable() 
          join row2 in dt2.AsEnumerable() 
          on row1.Field<int>("Code") equals 
          row2.Field<int>("Code") 
          select row1.ItemArray 
           .Concat(row2.ItemArray 
           .Where(r2 => 
            row1.ItemArray.Contains(r2) == false)).ToArray(); 
      foreach (object[] values in rowData) targetTable.Rows.Add(values); 
      return targetTable; 
     } 
    } 

Существует проблема с этой линией:

select row1.ItemArray.Concat(row2.ItemArray.Where(r2 => 
    row1.ItemArray.Contains(r2) == false)).ToArray(); 

Это, кажется, говорит, не включает меня, если это значение (а не столбцы) уже существует.

Я использую этот метод для объединения двух таблиц на основе столбца, который разделяет обе таблицы, но я хочу, чтобы в качестве конечного результата были уникальные столбцы с данными обеих таблиц.

Любые идеи?

ответ

1

Я не уверен, если я понимаю, ваше требование на 100%, но это:

row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false) 

отфильтрует те пункты, которые, случается, появляются в любом столбце таблицы 1, а не только столбец вы присоединяетесь на ,

Так что я хотел бы попробовать сделать это фильтр элемент на основе индекса, используя перегрузку метода Where расширения:

// Get the index of the column we are joining on: 
int joinColumnIndex = dt2.Columns.IndexOf("Code"); 

// Now we can filter out the proper item in the rowData query: 
row2.ItemArray.Where((r2,idx) => idx != joinColumnIndex) 

...

Нет, подождите. здесь:

var dt2FilterQuery = from dc in dt2Query.AsEnumerable() 
        where targetTable.Columns 
          .Contains(dc.ColumnName) == false 
        select dc; 

Вы отфильтровывая все столбцы таблицы 2, чье имя также отображается в таблице 1. Так что вы, вероятно, хотите, это:

public static DataTable DataTableJoiner(DataTable dt1, DataTable dt2) 
{ 
    DataTable targetTable = dt1.Clone(); 

    var dt2Query = dt2.Columns.OfType<DataColumn>().Select(dc => 
     new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, 
      dc.ColumnMapping)); 

    var dt2FilterQuery = from dc in dt2Query.AsEnumerable() 
         where !targetTable.Columns.Contains(dc.ColumnName) 
         select dc; 

    var columnsToAdd = dt2FilterQuery.ToArray(); 
    var columnsIndices = columnsToAdd.Select(dc => dt2.Columns.IndexOf(dc.ColumnName)); 

    targetTable.Columns.AddRange(columnsToAdd); 

    var rowData = from row1 in dt1.AsEnumerable() 
         join row2 in dt2.AsEnumerable() 
         on row1.Field<int>("Code") equals 
         row2.Field<int>("Code") 
         select row1.ItemArray 
          .Concat(row2.ItemArray 
          .Where((r2,idx) => 
           columnsIndices.Contains(idx))).ToArray(); 

    foreach (object[] values in rowData) targetTable.Rows.Add(values); 
    return targetTable; 
} 

Btw. Я не совсем понимаю, почему вы завершаете DataTable, который вы возвращаете в операторе using. Имхо - это бессмысленно распоряжаться тем объектом, который вы сразу возвращаете своему абоненту ...

+0

Точно, что мне нужно –

Смежные вопросы