Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.03.2019, 10:33   #1
dsbv
Пользователь
 
Регистрация: 21.03.2019
Сообщений: 20
По умолчанию требуется помощь с двойным циклом

Укажите на ошибку.
Есть ListView и текстовый файл, нужно пройти по строкам ListView и по строкам файла. Если данные в строке ListView и в строке файла совпадают, то строка в файле заменяется. Если совпадений в ListView и файле не найдено, то нужно в файл добавить данные из ListView
Не могу понять почему у меня дублируются строки
Код:
procedure TForm1.Button4Click(Sender: TObject);
var
  List_prodano,str_prodano:TStringList;
  i,i_pr:Integer;
begin  {
if ListView2.Items.Count=0 then
 begin
  showmessage('ListView пустой');
  exit;
 end;  }
 List_prodano:= TStringList.Create;
 List_prodano.LoadFromFile(ExtractFilePath( Application.ExeName )+'./prodano.txt');
for i := 0 to ListView2.Items.Count - 1 do
 begin
 ////////////////////////считалка и запись в prodano.txt//////////////////
 for i_pr := 0 to List_prodano.Count - 1 do
  begin
  str_prodano:= TStringList.Create;
  str_prodano.Delimiter := '|';
  str_prodano.DelimitedText:=List_prodano.Strings[i_pr];
  if (str_prodano[0]=ListView2.Items.Item[i].Caption) and (str_prodano[1]=ListView2.Items.Item[i].SubItems.Strings[0]) then
   begin
   List_prodano.Delete(i_pr);
   List_prodano.Insert(i_pr,ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2])) );
   end;
   if (str_prodano[0]<>ListView2.Items.Item[i].Caption) then
    begin
    List_prodano.Add(ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+ListView2.Items.Item[i].SubItems.Strings[2] );
    end;
   end;

 end;
     str_prodano.Free;
     List_prodano.SaveToFile(ExtractFilePath( Application.ExeName )+'./prodano.txt');
     List_prodano.Free;
/////////////////////////////end prodano.txt/////////////////////////////////

end;
dsbv вне форума Ответить с цитированием
Старый 21.03.2019, 11:35   #2
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,515
По умолчанию

Код:
if (str_prodano[0]<>ListView2.Items.Item[i].Caption) then begin // если одна из строк (ТЕКУЩАЯ строка) "файла" не совпала 
        List_prodano.Add(ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+ListView2.Items.Item[i].SubItems.Strings[2] );
      end;
а текущая строка ОБЯЗАТЕЛЬНО не совпадет с какой-либо ...
и значит мы также "обязательно" выполним добавление.
Цитата:
Не могу понять почему у меня дублируются строки
добавление надо делать ПОСЛЕ цикла поиска на основе признака который устанавливается (или НЕ устанавливается) в цикла поиска.
как правило это будет НОМЕР строки удовлетворяющей условию поиска.
или заведомо неверный( -1) для случая если поиск не увенчался успехом.

да и замену по сути тоже делать ВНЕ цикла поиска. (и на основе тех же данных)
Код:
findrow:=-1;
for j:=0 to len do begin
  if ... then findrow:=j;
end;

if findrow=-1 then 
  list.Add....
else 
 list.String[findrow]:=... Delete/Insert в одном флаконе
а еще можно для TStringList (TStrings)
Код:
findrow:=list.IndexOf(...);
Код:
  str_prodano:= TStringList.Create;
  ....
  str_prodano.Free;
должно ВЫПОЛНЯТЬСЯ одинаковое число раз.
Либо оба внутри цикла(одного и того же)
либо оба ВНЕ цикла (и это ПРЕДПОЧТИТЕЛЬНЕЙ).
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 21.03.2019 в 11:46.
evg_m вне форума Ответить с цитированием
Старый 21.03.2019, 12:10   #3
dsbv
Пользователь
 
Регистрация: 21.03.2019
Сообщений: 20
По умолчанию

Спасибо конечное за ответ. Но ничего не понял кроме вынести Add за цикл. Я новичок в delphi.
Вынес добавление за цикл-эффект тот же, неработает мой код
Код:
for i := 0 to ListView2.Items.Count - 1 do
 begin
  for i_pr := 0 to List_prodano.Count - 1 do
    begin
    str_prodano:= TStringList.Create;
    str_prodano.Delimiter := '|';
    str_prodano.DelimitedText:=List_prodano.Strings[i_pr];

    if (str_prodano[0]=ListView2.Items.Item[i].Caption) and (str_prodano[1]=ListView2.Items.Item[i].SubItems.Strings[0]) then
     begin
     List_prodano.Delete(i_pr);
     List_prodano.Insert(i_pr,ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2])) );
     end;
   end;

   if (str_prodano[0]<>ListView2.Items.Item[i].Caption) then
    begin
    List_prodano.Add(ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+ListView2.Items.Item[i].SubItems.Strings[2] );
    end;
 end;
dsbv вне форума Ответить с цитированием
Старый 21.03.2019, 13:04   #4
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,515
По умолчанию

Код:
str_prodano:= TStringList.Create; // создать ОДИН раз и пользоваться 
str_prodano.Delimiter := '|'; // настроить тоже достаточно ОДИН раз

for i := 0 to ListView2.Items.Count - 1 do
 begin
  
  findrow:=-1; // мы пока не знаем что в списке ЕСТЬ нужная нам строка
  for i_pr := 0 to List_prodano.Count - 1 do //проверим ВСЕ строки списка
    begin
    str_prodano.DelimitedText:=List_prodano.Strings[i_pr];

    if (str_prodano[0]=ListView2.Items.Item[i].Caption) and (str_prodano[1]=ListView2.Items.Item[i].SubItems.Strings[0]) then
     begin
     findRow:=i_pr; // мы УЗНАЛИ что нужно изменить ЭТУ строку
     List_prodano.Delete(i_pr);
     List_prodano.Insert(i_pr,ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2])) );
     end;
   end;
   // проверили ВСЕ строки списка и теперь
   if (str_prodano[0]<>ListView2.Items.Item[i].Caption) then
   if FindRow=-1 then // мы ни разу не нашли
    begin
    List_prodano.Add(ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+ListView2.Items.Item[i].SubItems.Strings[2] );
    end
   else // и если нашли 
   begin
  // str_prodano к концу цикла СОВСЕМ не та что нужно
    str_prodano.DelimitedText:=List_prodano.Strings[i_pr FindRow]; // поэтому получим ЕЩЕ разочек
{     List_prodano.Delete(i_prfindRow);
     List_prodano.Insert(i_prfindRow,ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2])) );}
// можно и оставить исправленное выше , но лучше 
     List_prodano.Strings[FindRow]:=ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2]));
   end;
 end;
str_prodano.Free; // мы один раз создали и один раз удалили!!!
конечно алгоритм ПРЕДПОЛАГАЕТ что в List_prodano НЕТ дублей. (мы при всем желании не найдем там ДВУХ строк подходящих ОДНОЙ и той же строке ListView
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 21.03.2019 в 13:15.
evg_m вне форума Ответить с цитированием
Старый 21.03.2019, 13:15   #5
dsbv
Пользователь
 
Регистрация: 21.03.2019
Сообщений: 20
По умолчанию

Спасибо за помощь.
Интересно мнение, с точки зрения программиста такой код сильно корявый?
Наконец то у меня поучилось ))))
Код:
Res:=False;
for i := 0 to ListView2.Items.Count - 1 do
 begin
 List_prodano:= TStringList.Create;
 List_prodano.LoadFromFile(ExtractFilePath( Application.ExeName )+'./prodano.txt');
  for i_pr := 0 to List_prodano.Count - 1 do
    begin
    str_prodano:= TStringList.Create;
    str_prodano.Delimiter := '|';
    str_prodano.DelimitedText:=List_prodano.Strings[i_pr];

    if (str_prodano[0]=ListView2.Items.Item[i].Caption) and (str_prodano[1]=ListView2.Items.Item[i].SubItems.Strings[0]) then
    begin
    Res:=True;
    List_prodano.Delete(i_pr);
    List_prodano.Insert(i_pr,ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+IntToStr(StrToInt(ListView2.Items.Item[i].SubItems.Strings[2])+ StrToInt(str_prodano[2])) );
    List_prodano.SaveToFile(ExtractFilePath( Application.ExeName )+'./prodano.txt');
    Break;
    end;
    if (str_prodano[0]<>ListView2.Items.Item[i].Caption) then  Res:=False;
  end; ///end for prodano
 if Res=False then
 begin
 List_prodano.Add(ListView2.Items.Item[i].Caption+'|'+ListView2.Items.Item[i].SubItems.Strings[0]+'|'+ListView2.Items.Item[i].SubItems.Strings[2] );
 List_prodano.SaveToFile(ExtractFilePath( Application.ExeName )+'./prodano.txt');
 end;
 List_prodano.Free;
 str_prodano.Free;
 end;//end for ListView
dsbv вне форума Ответить с цитированием
Старый 21.03.2019, 14:00   #6
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 19,042
По умолчанию

Код не форматирован

str_prodano создание во внутреннем цикле, освобождение во внешнем, утечки памяти гарантированы, разве что List_prodano.Count всегда = 1

что будет если на LoadFromFile исключение подымется? А подымется рано или поздно ) Аналогично для SaveToFile

и вообще стринглисты создавать в циклах зачем? Создать можно снаружи циклов, для очистки содержимого есть Clear, освобождать по выходу из процедуры

это еще без анализа логики )
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 21.03.2019, 14:26   #7
dsbv
Пользователь
 
Регистрация: 21.03.2019
Сообщений: 20
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
Код не форматирован

str_prodano создание во внутреннем цикле, освобождение во внешнем, утечки памяти гарантированы, разве что List_prodano.Count всегда = 1

что будет если на LoadFromFile исключение подымется? А подымется рано или поздно ) Аналогично для SaveToFile

и вообще стринглисты создавать в циклах зачем? Создать можно снаружи циклов, для очистки содержимого есть Clear, освобождать по выходу из процедуры

это еще без анализа логики )
Спасибо, я учел замечания evg_m, создание TStringList.Create и уничтожение вынес за циклы. Еще заметил, что в фале стали плодиться пустые строки, вставил код
Код:
for i:=List_prodano.count-1 downto 0 do
if trim(List_prodano[i])='' then List_prodano.delete(i);
А почему на LoadFromFile может исключение подняться, по каким причинам???
dsbv вне форума Ответить с цитированием
Старый 21.03.2019, 14:31   #8
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 19,042
По умолчанию

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

Последний раз редактировалось Аватар; 21.03.2019 в 14:34.
Аватар вне форума Ответить с цитированием
Старый 21.03.2019, 14:51   #9
dsbv
Пользователь
 
Регистрация: 21.03.2019
Сообщений: 20
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
Файл, например, не найден. Или открыт на запись другой программой. Или диск сбойнул в том секторе. Или файл найден, но в нем почему-то вместо килобайта инфы пару-тройку гиг, ну мало-ли) Полномочия еще. Можно еще придумать ) Это же обращение к внешним носителям информации
Про это я уже в курсе, при TForm1.FormCreate делаю проверки типа
Код:
 if not FileExists(ExtractFilePath( Application.ExeName )+'prodano.txt') then
dsbv вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[C++] Помощь с циклом for andryxa100 Помощь студентам 1 15.09.2017 08:42
Требуется помощь DanilovEV Фриланс 3 09.09.2014 18:00
Помощь с циклом manula Microsoft Office Excel 1 18.07.2014 04:52
Помощь с циклом (Не могу решить проблему) Usandy Паскаль, Turbo Pascal, PascalABC.NET 5 05.11.2013 16:41
Требуется помощь ! Garacio_cain Работа с сетью в Delphi 3 06.01.2008 14:53