Сравните два DataTables для определения строк в одной, но не другом

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

Исправил его, установив опцию:

Project -> Architecture -> Build Active Architecture Only

на Да

и компиляция и сборка проекта должным образом

17
задан Aaron 16 January 2013 в 20:44
поделиться

8 ответов

был бы, я должен выполнить итерации через каждую строку на каждом DataTable, чтобы проверить, являются ли они тем же.

Наблюдение, поскольку Вы загрузили данные из файла CSV, Вы не собираетесь иметь любые индексы или что-либо, так в какой-то момент, что-то оказывается перед необходимостью выполнять итерации через каждую строку, ли это быть Вашим кодом или библиотекой, или что бы то ни было.

Так или иначе, это - вопрос об алгоритмах, который не является моей специальностью, но мой наивный подход был бы следующие:

1: можно ли использовать какие-либо свойства данных? Уникальны все строки в каждой таблице, и действительно ли можно ли отсортировать их обоих по тем же критериям? Если так, можно сделать это:

  • Вид обе таблицы их идентификатором (использующий некоторую полезную вещь как quicksort). Если они уже отсортированы затем, Вы побеждаете большой.
  • Шаг через обе таблицы сразу, перескакивая через любые разрывы в идентификаторе в любой таблице. Средние дублированные записи подобранного идентификатора.

Это позволяет Вам выполнять в нем (время вида * 2) + одна передача, поэтому если бы мой big-O-notation корректен, это было бы (whatever-sort-time) + O (m+n), который довольно хорош.
(Пересмотр: это - подход, который О¤О–О©О¤О–О™ОџОҐ описывает )

2: альтернативный подход, который может быть более или менее эффективным в зависимости от того, насколько большой Ваши данные:

  • Пробегает таблицу 1, и для каждой строки, палка, это - идентификатор (или вычисленный хэш-код или некоторый другой уникальный идентификатор для той строки) в словарь (или хеш-таблица, если Вы предпочитаете называть ее этим).
  • Пробегает таблицу 2, и для каждой строки, видят, присутствует ли идентификатор (или хэш-код и т.д.) в словаре. Вы используете то, что словари имеют действительно быстро - O (1) я думаю? поиск. Этот шаг будет действительно быстр, но Вы заплатите цену, делающую все те, которых вводит словарь.

мне действительно было бы интересно видеть то, что люди с лучшим знанием алгоритмов, чем я придумывают для этого :-)

9
ответ дан 30 November 2019 в 11:04
поделиться

Принятие Вас имеет столбец ID, который имеет соответствующий тип (т.е. дает хэш-код и реализует равенство) - представляют в виде строки в этом примере, который является немного псевдокодом, потому что я не настолько знаком с DataTables и не имею времени для поиска всего этого сейчас :)

IEnumerable<string> idsInA = tableA.AsEnumerable().Select(row => (string)row["ID"]);
IEnumerable<string> idsInB = tableB.AsEnumerable().Select(row => (string)row["ID"]);
IEnumerable<string> bNotA = idsInB.Except(idsInA);
20
ответ дан 30 November 2019 в 11:04
поделиться

Можно использовать методы Слияния и GetChanges на DataTable, чтобы сделать это:

A.Merge(B); // this will add to A any records that are in B but not A
return A.GetChanges(); // returns records originally only in B
7
ответ дан 30 November 2019 в 11:04
поделиться

Ответы до сих пор предполагают, что Вы просто ищете, делают первичные дубликаты ключа. Это - довольно легкая проблема - можно использовать Слияние () метод, например.

, Но я понимаю Ваш вопрос означать, что Вы ищете дублирующийся DataRows. (Из Вашего описания проблемы, при этом обе таблицы были бы импортированы из файлов CSV, я даже предположил бы, что исходные строки не имели значений первичного ключа, и что любые первичные ключи присваиваются через AutoNumber во время импорта.)

наивная реализация (для каждой строки в A, сравните его ItemArray с той из каждой строки в B), действительно будет в вычислительном отношении дорогим.

А намного менее дорогой способ сделать это с алгоритмом хеширования. Для каждого DataRow свяжите строковые значения ее столбцов в единственную строку и затем назовите GetHashCode () на той строке для получения международного значения. Создайте Dictionary<int, DataRow>, который содержит запись, включил хэш-код, для каждого DataRow в Таблице данных B. Затем для каждого DataRow в DataTable вычислите хэш-код и посмотрите, содержится ли он в словаре. Если это не, Вы знаете, что DataRow не существует в Таблице данных B.

, Этот подход имеет два слабых мест, что оба появляются из того, что две строки могут быть неравными, но произвести тот же хэш-код. При нахождении строки в, чей хеш находится в словаре, затем необходимо проверить DataRow в словарь, чтобы проверить, что эти две строки действительно равны.

вторая слабость более серьезна: это маловероятно, но возможно, те два различных DataRows в B могли хешировать к тому же значению ключа. Поэтому словарь должен действительно быть Dictionary<int, List<DataRow>>, и необходимо выполнить проверку, описанную в предыдущем абзаце против каждого DataRow в списке.

Это берет изрядный объем работы для получения этой работы, но это - O (m+n) алгоритм, который я думаю, будет столь хорошим, как это добирается.

4
ответ дан 30 November 2019 в 11:04
поделиться

Спасибо за всю обратную связь.

у меня нет индекса, к сожалению. Я дам немного больше информации о своей ситуации.

у Нас есть программа создания отчетов (заменил отчеты Crystal), который установлен в 7 Серверах через ЕС. Эти серверы имеют много отчетов о них (не все равно для каждой страны). Они вызываются приложением командной строки, которое использует XML-файлы для их конфигурации. Таким образом, Один XML-файл может назвать несколько отчетов.

приложение командной строки планирует и управляет наш ночной процесс. Таким образом, XML-файл можно было назвать от нескольких мест.

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

я прохожу XML-файлы для всех ссылок, запрашивая программу планирования и создание списка всех отчетов. (это не слишком плохо).

проблема, которую я имею, я должен сохранить список всех отчетов, которые, возможно, были удалены из производства. Таким образом, я должен сравнить старый CSV с новыми данными. Для этого я думал, что это лучше всего поместило его в DataTables и сравнило информацию, (это могло быть неправильным подходом. Я предполагаю, что мог создать объект, который содержит его и выдерживает сравнение, различие затем создают, выполняют итерации через них).

данные, которые я имею о каждом отчете, следующие:

Строка - Строка Имени задачи - Интервал Имени Действия - ActionID (идентификатор Действия может быть в нескольких записях как единственное действие, может назвать много отчетов, т.е. XML-файл). Строка - XML-файл под названием Строка - Название Отчета

я попробую идею Слияния, данную MusiGenesis (спасибо). (перечитывающий некоторые сообщения, не уверенные, если Слияние будет работать, но стоящий попытки, поскольку я не услышал об этом прежде так что-то новое для изучения).

Идея HashCode звучит интересной также.

спасибо за весь совет.

1
ответ дан 30 November 2019 в 11:04
поделиться
public DataTable compareDataTables(DataTable First, DataTable Second)
{
        First.TableName = "FirstTable";
        Second.TableName = "SecondTable";

        //Create Empty Table
        DataTable table = new DataTable("Difference");
        DataTable table1 = new DataTable();
        try
        {
            //Must use a Dataset to make use of a DataRelation object
            using (DataSet ds4 = new DataSet())
            {
                //Add tables
                ds4.Tables.AddRange(new DataTable[] { First.Copy(), Second.Copy() });

                //Get Columns for DataRelation
                DataColumn[] firstcolumns = new DataColumn[ds4.Tables[0].Columns.Count];
                for (int i = 0; i < firstcolumns.Length; i++)
                {
                    firstcolumns[i] = ds4.Tables[0].Columns[i];
                }
                DataColumn[] secondcolumns = new DataColumn[ds4.Tables[1].Columns.Count];
                for (int i = 0; i < secondcolumns.Length; i++)
                {
                    secondcolumns[i] = ds4.Tables[1].Columns[i];
                }
                //Create DataRelation
                DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
                ds4.Relations.Add(r);
                //Create columns for return table
                for (int i = 0; i < First.Columns.Count; i++)
                {
                    table.Columns.Add(First.Columns[i].ColumnName, First.Columns[i].DataType);
                }
                //If First Row not in Second, Add to return table.
                table.BeginLoadData();
                foreach (DataRow parentrow in ds4.Tables[0].Rows)
                { 
                    DataRow[] childrows = parentrow.GetChildRows(r);

                    if (childrows == null || childrows.Length == 0)
                        table.LoadDataRow(parentrow.ItemArray, true);
                    table1.LoadDataRow(childrows, false);

                }
                table.EndLoadData();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return table;
}
1
ответ дан 30 November 2019 в 11:04
поделиться

Просто к вашему сведению:

Вообще говоря, об алгоритмах, сравнивая два набора поддающихся сортировке (поскольку идентификаторы обычно) не O (M*N/2) операция, но O (M+N), если два набора заказаны. Таким образом, Вы сканируете одну таблицу с указателем на запуск другого, и:

other_item= A.first()
only_in_B= empty_list()
for item in B:
    while other_item > item:
        other_item= A.next()
        if A.eof():
             only_in_B.add( all the remaining B items)
             return only_in_B
    if item < other_item:
         empty_list.append(item)
return only_in_B

код выше является, очевидно, псевдокодом, но должен дать Вам общую суть, если Вы решаете кодировать его сами.

1
ответ дан 30 November 2019 в 11:04
поделиться
        try
        {
            if (ds.Tables[0].Columns.Count == ds1.Tables[0].Columns.Count)
            {
               for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
               {
                    for (int j = 0; j < ds.Tables[0].Columns.Count; j++)
                   {
       if (ds.Tables[0].Rows[i][j].ToString() == ds1.Tables[0].Rows[i][j].ToString())
                       {


                        }
                        else
                        {

                           MessageBox.Show(i.ToString() + "," + j.ToString());


                       }

                                               }

                }

            }
            else
            {
               MessageBox.Show("Table has different columns ");
            }
        }
        catch (Exception)
        {
           MessageBox.Show("Please select The Table");
        }
0
ответ дан 30 November 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: