C # Тип данных для большой отсортированной коллекции с позицией? - PullRequest
4 голосов
/ 17 сентября 2008

Я пытаюсь сравнить два больших набора данных из запроса SQL. Прямо сейчас SQL-запрос выполняется извне, и результаты каждого набора данных сохраняются в его собственном CSV-файле. Мое маленькое консольное приложение C # загружает два текстовых / CSV-файла, сравнивает их на предмет различий и сохраняет различия в текстовом файле.

Это очень простое приложение, которое просто загружает все данные из первого файла в массив и выполняет .compare () для массива, когда каждая строка читается из второго файла CSV. Затем сохраняет записи, которые не совпадают.

Приложение работает, но я хотел бы улучшить производительность. Я полагаю, что могу значительно повысить производительность, если смогу воспользоваться тем, что оба файла отсортированы, но я не знаю тип данных в C #, который сохраняет порядок и позволил бы мне выбрать конкретную позицию. Есть базовый массив, но я не знаю, сколько элементов будет в каждом списке. Я мог иметь более миллиона записей. Есть ли доступный тип данных, на который я должен смотреть?

Ответы [ 11 ]

2 голосов
/ 17 сентября 2008

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

StreamReader one = new StreamReader("C:\file1.csv");
StreamReader two = new StreamReader("C:\file2.csv");
String lineOne;
String lineTwo;

StreamWriter differences = new StreamWriter("Output.csv");
while (!one.EndOfStream)
{
    lineOne = one.ReadLine();
    lineTwo = two.ReadLine();
    // do your comparison.
    bool areDifferent = true;

    if (areDifferent)
        differences.WriteLine(lineOne + lineTwo);
}

one.Close();
two.Close();
differences.Close();
1 голос
/ 17 сентября 2008

Это адаптация кода Дэвида Сокола для работы с переменным количеством строк, с выводом строк, которые находятся в одном файле, но не в другом:

StreamReader one = new StreamReader("C:\file1.csv");
StreamReader two = new StreamReader("C:\file2.csv");
String lineOne;
String lineTwo;
StreamWriter differences = new StreamWriter("Output.csv");
lineOne = one.ReadLine();
lineTwo = two.ReadLine();
while (!one.EndOfStream || !two.EndOfStream)
{
  if(lineOne == lineTwo)
  {
    // lines match, read next line from each and continue
    lineOne = one.ReadLine();
    lineTwo = two.ReadLine();
    continue;
  }
  if(two.EndOfStream || lineOne < lineTwo)
  {
    differences.WriteLine(lineOne);
    lineOne = one.ReadLine();
  }
  if(one.EndOfStream || lineTwo < lineOne)
  {
    differences.WriteLine(lineTwo);
    lineTwo = two.ReadLine();
  }
}

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

1 голос
/ 17 сентября 2008

System.Collections.Specialized.StringCollection позволяет добавлять диапазон значений и, используя метод .IndexOf (string), позволяет получать индекс этого элемента.

При этом вы, вероятно, могли бы просто загрузить пару байтов [] из файлового потока и выполнить сравнение байтов ... даже не беспокойтесь о загрузке этого материала в формальную структуру данных, такую ​​как StringCollection или string []; если все, что вы делаете, это проверяете различия, и вам нужна скорость, я бы сказал, что разница в байтах - это то, где она находится.

0 голосов
/ 18 сентября 2008

Чтобы решить вопрос № 1, я бы порекомендовал изучить создание хэша каждой строки. Таким образом, вы можете быстро и легко сравнивать хэши, используя словарь.

Чтобы решить вопрос № 2, одним из быстрых и грязных решений было бы использование IDictionary. Использование itemId в качестве вашего первого строкового типа и остальной части строки в качестве второго строкового типа. Затем вы можете быстро найти, существует ли itemId, и сравнить строки. Это, конечно, предполагает .Net 2.0 +

0 голосов
/ 17 сентября 2008

Если у вас есть два файла, каждый из которых содержит миллион строк, как указано в вашем сообщении, вы можете использовать много памяти. Некоторые проблемы с производительностью могут быть связаны с заменой диска. Если вы просто сравниваете строку 1 файла A с строкой 1 файла B, файла строки A -> файла строки 2 B и т. Д., Я бы порекомендовал метод, который не хранит так много в памяти. Вы можете либо прочитать списки двух файловых потоков, как было опубликовано предыдущим комментатором, и записать свои результаты «в режиме реального времени» по мере их обнаружения. Это не будет явно хранить что-либо в памяти. Вы также можете помещать куски каждого файла в память, скажем, по тысяче строк за раз, в нечто вроде списка. Это может быть точно настроено для удовлетворения ваших потребностей.

0 голосов
/ 17 сентября 2008

Я думаю, что причина, по которой у всех так много разных ответов, заключается в том, что вы не достаточно четко сформулировали свою проблему, чтобы на нее можно было ответить. Во-первых, это зависит от того, какие различия вы хотите отслеживать. Вы хотите, чтобы различия выводились, как в WinDiff, где первый файл - «оригинальный», а второй - «измененный», чтобы вы могли перечислить изменения как INSERT, UPDATE или DELETE? Есть ли у вас первичный ключ, который позволит вам сопоставить две строки как разные версии одной и той же записи (когда поля, отличные от первичного ключа, отличаются)? Или это какое-то согласование, когда вы просто хотите, чтобы выходные данные вашей разницы говорили что-то вроде «ЗАПИСАТЬ В ФАЙЛ 1, А НЕ ФАЙЛ 2»?

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

0 голосов
/ 17 сентября 2008

У меня есть один вопрос: рассматривали ли вы "аутсорсинг" своего сравнения. Есть много хороших инструментов сравнения, к которым вы могли бы просто обратиться. Я был бы удивлен, если бы не один, который позволил бы вам указать два файла и получить только различия. Просто мысль.

0 голосов
/ 17 сентября 2008

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

0 голосов
/ 17 сентября 2008

Если вы просто хотите посмотреть, включены ли все строки в FileA в FileB, вы можете прочитать его и просто сравнить потоки внутри цикла.

Файл 1 entry1 entry2 Entry3

Файл 2 entry1 Entry3

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

0 голосов
/ 17 сентября 2008

Вы можете легко использовать SortedList для быстрого поиска. Если загружаемые данные уже отсортированы, вставка в SortedList не должна быть медленной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...