Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > TObjectList и работа с ним


Автор: 1122 25.5.2010, 16:47
Создаю объект TobjectList. Заполняю. Далее нужно оставить половину элементов от того, что есть. Перегоняю эту половину во временный ObjectList и хочу очистить исходный, чтобы затем вернуть туда эти элементы из временного. Но сыпятся ошибки после того, как я пытаюсь вызвать clear или delete по элементно.
Как правильно очищать такие массивы?

Выдержки из кода:
Код

 procedure TForm1.FormCreate(Sender: TObject);
begin
Population:=TobjectList.Create;
TempPopulation:=TobjectList.Create;
end;


Таким способом первоначально формирую массив:
Код

for i:=0 to N-1 do
begin
    Osob:=TOsob.Create;
    Osob.fenotip:=-3 + i*0.12;
    Osob.P:= 0.2*osob.fenotip+osob.fenotip*sin(8.9*osob.fenotip)+0.9*cos(1.5*osob.fenotip-2);
    Osob.genotip:=inttobin(i,col);
    Population.add(osob);
end;


Далее массив дозаполняется элементами:

Код

for i:=0 to count-1 do
begin
Osob2:=Tosob.create;
Osob2.genotip:=agen1[i];
Population.Add(Osob2);
end;

for i:=0 to count-1 do
begin
Osob2:=Tosob.create;
Osob2.genotip:=agen2[i];
Population.Add(Osob2);
end;


for i:=0 to Population.Count-1 do
begin
(Population.Items[i] as Tosob).fenotip:= -3 + i*r;
x:= -3 + i*r;
(Population.Items[i] as Tosob).P:=  0.2*x+x*sin(8.9*x)+0.9*cos(1.5*x-2);
end;


И вот дальше нужно оставить в Population только N значений. Как это сделать?
Спасибо.




Автор: Dom 25.5.2010, 17:09
Если все равно какие элементы удалять, то можно например так

Код

for i := Population.Count - 1 downto N do
  Population.Delete(i);

Автор: 1122 25.5.2010, 17:21
Вбил ваш код. Ошибка. Аксесс виалэйшен.

Автор: 1122 25.5.2010, 18:03
Странные дела.

Если написать такой код:
Код

for i := 50 to population.count do
Population.Delete(i);

и этот самый каунт будет равен 92, то на 71 итерации, когда будет удаляться 71 элемент произойдет ошибка.Т.к. удаляя на первой итерации 50-тый элемент каунт уменьшается на один и т.д. Когда дойдем до 71 итерации и нужно будет удалить 71й элемент, то его уже не будет.
Что можно сделать?

Автор: kami 25.5.2010, 19:15
Цитата(1122 @  25.5.2010,  18:03 Найти цитируемый пост)
Странные дела.

Ничего странного. Пойдем по порядку.

Цитата(1122 @  25.5.2010,  16:47 Найти цитируемый пост)
нужно оставить половину элементов от того, что есть. Перегоняю эту половину во временный ObjectList и хочу очистить исходный, чтобы затем вернуть туда эти элементы из временного. 

По умолчанию ObjectList является владельцем элементов, которые он содержит. Это значит, что при удалении объекта из него, или при очищении списка этот объект УНИЧТОЖАЕТСЯ. Если нужно, чтобы этого не происходило, то конструктор вызывать нужно так:
Код

Population:=TobjectList.Create(False);

Но нужно четко осознавать, что в этом случае об освобождении объектов, добавленных в список, нужно позаботиться самому, иначе пойдут утечки.
При Вашем способе (загнать половину во временный список, очистить исходный, перенести обратно) получается следующая последовательность:
1. В исходном списке содержатся ссылки на объекты.
2. Часть этих ссылок мы копируем во временный список.
3. Очищаем исходный список. При этом, т.к. список был создан с конструктором по-умолчанию, он является владельцем добавленных в него объектов. При очищении он высвобождает все содержащиеся в нем объекты, ссылки на них становятся не-валидными.
4. Копируем ссылки на (уже уничтоженные) объекты в исходный список. Но толку от них уже нет...

Цитата(1122 @  25.5.2010,  16:47 Найти цитируемый пост)
И вот дальше нужно оставить в Population только N значений. Как это сделать?

Код, предложенный Dom правильный. Вы не обратили внимание на то, что используется цикл на уменьшение for ...downto, а не for...to.
В случае использования этого кода настоятельно рекомендуется оставить ObjectList владельцем объектов.

Добавлено @ 19:20
Цитата(kami @  25.5.2010,  19:15 Найти цитируемый пост)
используется цикл на уменьшение for ...downto

В дополнение: так как индексация элементов в списке начинается с нуля, прошу обратить внимание на
Цитата(Dom @  25.5.2010,  17:09 Найти цитируемый пост)
for i := Population.Count - 1 downto N do


Автор: underchronos 25.5.2010, 20:49
kami
А не проще тогда в этом цикле воспользоваться функцией Extract?

Код

for i := Population.Count - 1 downto N do
  TempPopulation.Add(Population.Extract(i));


Разве для этого метода будет важно с каким флагов Create? Он удалит ссылку из своего списка и вернет ее, не удалив сам объект.


Автор: kami 25.5.2010, 21:27
Цитата(underchronos @  25.5.2010,  20:49 Найти цитируемый пост)
А не проще тогда в этом цикле воспользоваться функцией Extract?

"Из любого безвыходного положения есть по меньшей мере два выхода" (с) не помню чье.
Возможно, Вам проще сделать так.
Но мне было бы лень заводить второй список, тратить время процессора на его создание/заполнение/копирование_в_исходный/уничтожение, когда можно просто воспользоваться кодом Dom, зная при этом что OwnObjects=True.
Всё зависит от задачи...

Upd: в Вашем случае при перегоне из временного в основной также нужно будет пользоваться Extract, в противном случае - опять контроль OwnObjects временного списка...

Автор: underchronos 25.5.2010, 21:33
Цитата(kami @  25.5.2010,  21:27 Найти цитируемый пост)
"Из любого безвыходного положения есть по меньшей мере два выхода" (с) не помню чье.

Надо запомнить!  smile 


Цитата(kami @  25.5.2010,  21:27 Найти цитируемый пост)
Всё зависит от задачи...

Да я, честно признаться, задачу не понимаю.  smile  Я понял из слов создателя топика -- нужно перегнать часть исходного списка в другой. А потом вернуть его по необходимости если что...  Или он хочет просто очистить половину исходного списка. 

Автор: kami 25.5.2010, 21:44
Цитата(underchronos @  25.5.2010,  21:33 Найти цитируемый пост)
Я понял из слов создателя топика -- нужно перегнать часть исходного списка в другой. 

Вообще-то исходная проблема звучала как
Цитата(1122 @  25.5.2010,  16:47 Найти цитируемый пост)
И вот дальше нужно оставить в Population только N значений. Как это сделать?

И решение было дано в первом же ответе smile

Кстати, чем-то этот код напоминает пример игры на Паскале из учебников - "Цивилизация" (не путать со стратегией). Там по определенным условиям в "соседних" клетках "рождались" новые элементы, старели (просто от этапа к этапу), умирали от перенаселенности (когда в 3 или 4 соседних клетках тоже были элементы) и т.п...

Автор: bems 26.5.2010, 00:01
kami, это жизнь а не цивилизация

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)