Перемешать текстовый файл с исходным кодом Delphi или что-нибудь еще

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

Я хочу сохранить его на диске, а затем перетасовать файл другим методом.

Какие-либо предложения?


person Hein du Plessis    schedule 21.10.2009    source источник


Ответы (4)


Как реализована ваша процедура перемешивания? Особенно рутинный обмен? Если вы написали свое собственное, в следующих строках:

vTempSrting := vStringList[I]; 
vStringList.Delete(I); 
vStringList.Insert(J,vTempString);

это будет очень медленно. Используйте метод обмена в списке строк.

Этот код занял 78 мс на моем довольно среднем (3-летнем) компьютере:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,Classes,uIntegerList,Windows,Math;

procedure Shuffle(aSL : TStringList);
var I,J : integer;
begin
  for I := 0 to aSL.Count-1 do
  begin
    J := randomrange(I,aSL.Count);
    aSL.Exchange(I,J);
  end;
end;

procedure CreateTestFile;
var
  vSL : TStringList;
  I : integer;
begin
  vSL := TStringList.Create;
  try
    for I := 1 to 100000 do vSL.Add('Sample text #'+inttostr(I));
    vSL.SaveToFile('c:\test.txt');
  finally
    vSL.Free;
  end;
end;

function TestShuffle : longword;
var
  vSL : TStringList;
  vTick0 : longword;
begin
  vSL := TStringList.Create;
  try
    vTick0 := gettickcount;
    vSL.LoadFromFile('c:\test.txt');
    Shuffle(vSL);
    vSL.SaveToFile('c:\test.txt');
    Result := gettickcount - vTick0;
  finally
    vSL.Free;
  end;
end;

begin
  CreateTestFile;
  writeln(TestShuffle,' ms');
  readln;
end.
person Svein Bringsli    schedule 21.10.2009
comment
Вау, спасибо за код, svein! Я действительно использую обмен, но я только что изложил свою проблему - строки передаются в мою процедуру перетасовки из памятки - и, очевидно, с каждым обновлением памятка должна обновлять 10 000 визуальных элементов !! Теперь я использую промежуточный AstrinList, сортирую его и затем возвращаю в заметку: aStringLIst: = TStringList.Create; aStringList.Assign (mNumbers.Lines); Перемешать (aStringList); mNumbers.Lines.Assign (aStringList); aStringList.Free; Это мгновенно! Большое спасибо - person Hein du Plessis; 21.10.2009
comment
Ничего себе, комментарии действительно испортили мой код, извините, надеюсь, вы сможете разобраться. - person Hein du Plessis; 21.10.2009
comment
Чтобы избежать визуальных обновлений, используйте BeginUpdate и EndUpdate: mNumbers.Lines.BeginUpdate; Перемешать (mNumbers.Lines); mNumbers.Lines.EndUpdate; - person jasonpenny; 21.10.2009

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

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

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

person Argalatyr    schedule 21.10.2009
comment
Я использую TStringList, но проблема в том, что доступ к чему-либо в нем занимает много времени, поэтому сканирование сверху вниз занимает минуты. Это просто список чисел, поэтому я, вероятно, могу загрузить его в массив и перемешать. Мне нравятся функции TStringList, возможно, есть индексированный TStringList или что-то в этом роде? - person Hein du Plessis; 21.10.2009

Простой способ - сгенерировать список случайных чисел, отсортировать его, а затем выполнить попарную замену данных позже. Сортировка может выполняться по алгоритму o (n * log (n)), тогда как замена всегда выполняется по алгоритму o (n), что намного быстрее.

На всякий случай, если вы не подумали об этом, оставьте данные как есть и просто сохраните дополнительный перетасованный индекс.

person Lars D    schedule 21.10.2009

Раньше я задавал вопрос о создании перетасованного диапазона - вместо того, чтобы создавать список чисел и затем перетасовывать их, мне нужна была функция, которая могла бы итеративно возвращать список перетасованных чисел без затрат памяти O (n):

Генерация перемешанного диапазона с использованием PRNG вместо перемешивания

Если вы создаете какой-то индекс для своего файла на диске, вы можете создать перетасованную версию, не платя за память, что может быть важно для очень больших файлов. Для индекса я предлагаю что-нибудь простое, например, плоский поток позиций (как 32- или 64-битные целые числа) начала каждой строки. Таким образом, чтобы извлечь N-ю строку из текстового файла, вы можете просто выполнить поиск в потоке индекса до N * 4 (или N * 8 для 64-битных индексов), чтобы определить смещение начала строки, а затем выполнить поиск эту позицию в потоке текстового файла и зачитайте строку.

Используя этот подход, вы можете перемешивать очень большие файлы, не тратя на это затраты в памяти. Конечно, перетасовка будет означать случайное извлечение строк из исходного файла, что не будет столь же эффективным, как сортировка в памяти, если только файл не очень маленький (помещается в кеш почти при первом доступе) или очень большой (в этом случае происходит переполнение памяти. будет хуже, чем случайный поиск), или, возможно, если вы не используете механический жесткий диск (например, SSD).

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

person Barry Kelly    schedule 21.10.2009
comment
Спасибо, Барри, хотя я обнаружил, что моя ошибка связана с визуальным обновлением элемента управления с функцией перемешивания. Но интересный подход! - person Hein du Plessis; 23.10.2009