Сравните со списком строк

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

Мой код будет выглядеть так

var
  aFirstStrList: TStringList ;
  aSecondStringList: TStringList; 
  MissingElement_firstElement_not_inside_second: TStringList;
  MissingElement_SecondElement_not_inside_First: TStringList;

...

for i := 0 to aFirstStrList.Count - 1 do
begin
  if aSecondStringList.IndexOf(aFirstStrList[i] < 0 ) then
  begin
    // react on not found elements 
    ....
    MissingElement_firstElement_not_inside_second.add(...);
  end;
end;
// and now same code just opposite search direction .... 
....

person Franz    schedule 27.07.2013    source источник
comment
Это зависит от ... пожалуйста, уточните разницу. Просто подумайте о a;b и a;a. Какой результат вы хотели бы получить в этом случае?   -  person Sir Rufo    schedule 27.07.2013


Ответы (3)


Вместо использования IndexOf сначала отсортируйте оба списка, чтобы предотвратить поиск по всему списку в каждом цикле. Более того, это можно сделать за один цикл.

Предполагая, что вы хотите получить результаты в двух отдельных списках строк, попробуйте следующее:

procedure CompareStringLists(List1, List2: TStringList;
  Missing1, Missing2: TStrings);
var
  I: Integer;
  J: Integer;
begin
  List1.Sort;
  List2.Sort;
  I := 0;
  J := 0;
  while (I < List1.Count) and (J < List2.Count) do
  begin
    if List1[I] < List2[J] then
    begin
      Missing2.Add(List1[I]);
      Inc(I);
    end
    else if List1[I] > List2[J] then
    begin
      Missing1.Add(List2[J]);
      Inc(J);
    end
    else
    begin
      Inc(I);
      Inc(J);
    end;
  end;
  for I := I to List1.Count - 1 do
    Missing2.Add(List1[I]);
  for J := J to List2.Count - 1 do
    Missing1.Add(List2[J]);
end;

Использование:

procedure TForm1.Button1Click(Sender: TObject);
var
  List1: TStringList;
  List2: TStringList;
begin
  List1 := TStringList.Create;
  List2 := TStringList.Create;
  try
    List1.CommaText := 'A, C, F, G, H, K, L, M, N, O, Q, R';
    List2.CommaText := 'C, D, E, F, J, P, Q, S, T, U, V, W';
    Memo1.Lines.Assign(List1);
    Memo2.Lines.Assign(List2);
    CompareStringLists(List1, List2, Memo3.Lines, Memo4.Lines);
  finally
    List2.Free;
    List1.Free;
  end;
end;
person NGLN    schedule 27.07.2013

Лучшая производительность:
Сортировка списков входных строк
Сравните с алгоритмом, аналогичным объединению отсортированных списков(там вы найдете то, чего не хватает в каждом списке)

Проще, но медленнее:
Копировать списки строк в результирующие списки строк
Один цикл для первого списка строк (используйте обратный цикл для этого for Count-1 downto 0 do)
Поиск той же строки во втором, если найдено - удалить из обоих списков
Различия будут оставаться в списках строк

person VitaliyG    schedule 27.07.2013

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

Либо нужно установить сортировку с учетом регистра

List1.CaseSensative := true ;
List1.Sort ;
List2.CaseSensative := true ;
List2.Sort ;

OR

Сделайте сравнения нечувствительными к регистру

если ВерхнийРегистр(Список1[I]) ‹ ВерхнийРегистр(Список2[J]), то

и

else if UpperCase(List1[I]) > UpperCase(List2[J]) then

соответственно.

person Steve    schedule 21.03.2017