![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Есть ли функция для удаления 1 элемента из динамического масива? [D6, Win2k]
bloodman © (2004-09-01 19:54:00)Есть ли функция для удаления 1 элемента из динамического масиваб и последующим изменением его длины??
А то не хочется писать свою, наверняка же есть...
bloodman (2004-09-08 00:01:00) [1]Спасибо за совет! Попробую сделать так.
Defunct (2004-09-07 21:06:00) [2]Конструктивный совет по улучшению вашей программы:
Откажитесь от Record, создайте класс TDataCell, в котором разместите все поля, добавьте в этот класс методы для работы с полями, сохранение/восстановление/удаление и прочее. Создайте наследника, TDataControl в котором, например, будет множество полей, и перекройте базовые методы, методами работы с множеством.
Например:
Type
TSmallString = String[255];
TDataCell = class
Private
FID : Integer;
FFather : Integer;
FName : TSmallString;
FPath : TSmallString;
FParameters : TSmallString;
FShortcut : TSmallString;
FIconPath : TSmallString;
FEnabled : Boolean;
FDeleted : Boolean;
FServed : Boolean;
FChanged : Boolean;
Procedure SetName(AName: TSmallString);
Procedure SetPath(APath: TSmallString);
Procedure SetParams( AParams: TSmallString);
Procedure SetShortcut( AShortcut: TSmallString);
Procedure SetIconPath(APath: TSmallString);
Public
Property Enabled:Boolean Read Enabled;
Property Deleted:Boolean Read Deleted
Property Name:TSmallString Read FName Write SetName;
Property Path:TSmallString Read FPath Write SetPath;
Property Params:TSmallString Read FParams Write SetParams;
Property Shortcut:TSmallString Read FShortcut Write SetShortcut;
Property IconPath: TSmallString Read FIconPath Write SetIconPath;
Procedure PrepareToDoSomthing; Virtual;
Procedure DoSomething; Virtual;
....
и т.д. все что вам требуется выполнять над полями.
....
Procedure Save(Stream: TMemoryStream); Virtual;
Procedure Load(Stream: TMemoryStream); Virtual;
Constructor Create; Virtual;
Destructor Destroy; Virtual;
end;
TDataControl = class(TDataCell)
Private
FCount : Integer;
DataCells : Array of TDataCell
Procedure SetCell( Index:Integer; ACell: TDataCell);
Function GetCell( Index:Integer):TDataCell;
Public
Property Count: Integer Read FCount;
Property Items[Index: Integer]:TDataCell Read GetCell Write SetCell;
Procedure Add:TDataCell; Virtual;
Procedure PrepareToDoSomthing; Override;
Procedure DoSomething; Override;
....
и т.д. все что вам требуется выполнять над полями.
....
Procedure Save(Stream: TMemoryStream); Override;
Procedure Load(Stream: TMemoryStream); Override;
Constructor Create; Override;
Destructor Destroy; Override;
End;
Опишете так, зато потом будет проще работать. Например все сведется к:
Var DB : TDataControl;
Begin
DB := TDataControl.Create;
DB.Load( Stream );
DB.PrepareToDoSomething;
DB.DoSomething;
DB.Save( Stream );
DB.Free;
End;
Defunct (2004-09-07 20:40:00) [3]> В процедуре я обрабатываю масив, чтобы не запоминать с какими жлементами я работал уже я их удаляю. Но потом вне этой функции я снова должен использовать этот масив. Вот поэтому мне нужна его копия внутри процедуры.
Вот с этого надо было и начинать, т.е. ваша цель выполнить какие-то действия над данными однократно. Решается это добавлением дополнительного поля в структуру данных с именем скажем: FServed:Boolean или FNeedProcessing:Boolean. Перед работой со всем массивом установите в каждой записи FNeedProcessing в True, а после выполнения действия сбрасывайте этот флажек.
Procedure PrepareToDoSomething( DynArray: TYourDinamicArray);
var I:Integer;
Begin
For I:=0 To Length(DynArray)-1 Do DynArray[i].FNeedProcessing := True;
End;
Procedure DoSomething( DynArray: TYourDynamicArray);
Var I:Integer;
Begin
For I:=0 To Legnth( DynArray)-1 Do
If DynArray[i].FNeedProcessing Then
Begin
DynArray[i].FNeedProcessing := False;
..
<тут ваши действия над данными>
End;
End;
> Как лучше создать его копию.Я просто копирую элемент за элементом но ведь это медленно очень, пробовал с Copymem не получилось.
Да вы правы, это очень медленно. Особенно если много данных, то никто никогда не делает полное копирование.
bloodman (2004-09-07 20:23:00) [4]>Создайте копию массива внутри функции вручную, и работайте с ней.
Это мне и нужно. Как лучше создать его копию.Я просто копирую элемент за элементом но ведь это медленно очень, пробовал с Copymem не получилось.
>Вопрос, зачем все это надо???
В процедуре я обрабатываю масив, чтобы не запоминать с какими жлементами я работал уже я их удаляю. Но потом вне этой функции я снова должен использовать этот масив. Вот поэтому мне нужна его копия внутри процедуры.
Defunct (2004-09-06 23:13:00) [5]> Мне требуется передать в функцию динамический масив. В ней я постепенно удаляю все его элементы.Но мне нужно что бы этот масив остался в сохранностивне функции т.е. в ней нужно работать с его конией поэтому у меня в функции параметра VAR перед масивом нет.
Стоп. Здесь противоречие, зачем удалять элементы так, чтобы ничего не удалялось? Где логика? Сформулируйте пожалуйста цель вашего, как бы это лучше выразиться, шаманства.
> НО все равно из него удаляется элемент при первом вызове процедуры move - это и есть моя проблема.
Ответ на вопрос "почему удаляются элементы вне функции?" прост - динамический массив предствляет собой указатель на массив. Создайте копию массива внутри функции вручную, и работайте с ней.
Вопрос, зачем все это надо???
bloodman (2004-09-06 22:44:00) [6]Defunct © (06.09.04 00:11) [18]
>>Ну и раз уж у вас получается непонятно что. То будьте добры не >>ходите вокруг да около с возгласами:
>>> Собственно херня ета происходит на move (или на for без >>разници) причем при первом вызове
>>А сформулируйте вопрос нормально. Что именно вы хотите сделать?
ок . Мне требуется передать в функцию динамический масив. В ней я постепенно удаляю все его элементы.Но мне нужно что бы этот масив остался в сохранности вне функции т.е. в ней нужно работать с его конией поэтому у меня в функции параметра VAR перед масивом нет. НО все равно из него удаляется элемент при первом вызове процедуры move - это и есть моя проблема.
Erik1 (2004-09-06 13:35:00) [7]To Romkin
Я думаю, что вот это "куча (двоичная, биномиальная...), двоичное дерево" автор за ругательство примет :)
Romkin (2004-09-06 11:58:00) [8]Defunct © (06.09.04 00:11) [18] ТАк код TList посмотреть можно. И даже рекомендуется :)
Там фактически динамический массив, но только растет, не уменьшается. И, кстати, сделано весьма грамотно: это не dynamic array, а указатель на тип массив. Память же выделяется блоками, с запасом.
Вообще говоря, тип данных для хранения структуры выбирать надо строго исходя из тех действий, которые будут делаться. А абстрактных типов данных довольно много, выбор есть. Навскидку: массив, список (однонаправленный, двунаправленный, многосвязный), куча (двоичная, биномиальная...), двоичное дерево и тд :))
Erik1 (2004-09-06 10:04:00) [9]Интересная у тебя функция Create(DB : TDBDinArray):boolean, вот бы еще узнать, что у тебя в I присваевается. :)
К томуже ненадо выкидавать переменую Size.
Defunct (2004-09-06 00:11:00) [10]> Для чего это нужно было приводить не понятно. Вопрос был не в том КАК это сделать, а в том что почему-то удаляется элемент из основного масива, хотя не должен...
Сюдя из Ваших постингов это понять нельзя, более того, вообще непонятно какое отношение имеет название функции "Create"- создать к первоначальному вопросу "Как удалить" т.е. "Delete".
> Procedure Delete(var DynArray: TYoursDynamicArray; ItemIndex: Integer);
Идем далее, выделенный varв заголовке приведенной мной процедуры задает область действия процедуры на основной массив, т.е. тот массив (DynArray), который будет передаваться в процедуру как параметр. Если не требуется удалять элемент массива, тогда вы можете убрать оттуда var, и элемент из основного массива удаляться не будет.
Ну и раз уж у вас получается непонятно что. То будьте добры не ходите вокруг да около с возгласами:
> Собственно херня ета происходит на move (или на for без разници) причем при первом вызове
А сформулируйте вопрос нормально. Что именно вы хотите сделать?
> Односвязный список - это TList??
Односвязный список - это односвязный список. Например, такой:
PDataRec = ^TDataRec;
TDataRec = Record
MyData : TMyData;
Next: PDataRec;
End;
У вас должны быть 2 указателя, на голову списка (1-й элемент) и, необязательно, на хвост списка (последний элемент). Промежуточные элементы всталяются в цепочку с помощью указателя Next
Работать с таким списком так:
P := Head;
While P<>Nil Do P := P.Next;
Выбрасывать (удалять) элемент:
P2 := P.Next;
P.Next := P2.Next;
Dispose(P2);
А TList - это TList, и неизвестно, что в него Borland вставил, является он односвязным списком или нет, нужно смотреть по коду.
bloodman (2004-09-05 23:47:00) [11]Defunct © (05.09.04 23:37) [16]
Ваща процедура аналогична моей , даже больше , это одно и тоже .
Для чего это нужно было приводить не понятно. Вопрос был не в том КАК это сделать, а в том что почему-то удаляется элемент из основного масива, хотя не должен...
Односвязный список - это TList??
Defunct (2004-09-05 23:37:00) [12]Там где часто приходится удалять. Лучше использовать динамический односвязный список, а не массив.
тогда удаление сводится к двум действиям:
- освобождение памяти
- выброс элемента из цепочки.
Возвращаясь к вашему вопросу. Удаление элемента из динамического массива - действие трудоемкое, но осуществимое.
Procedure Delete( varDynArray: TYoursDynamicArray; ItemIndex: Integer);
Var I:Integer;
Begin
If ItemIndex< Length(DynArray) Then
Begin
For I:=ItemIndex +1To Length(DynArray) -1Do DynArray[i-1] := DynArray[i];
SetLength(DynArray, Length(DynArray)-1);
End;
End;
bloodman (2004-09-05 21:49:00) [13]что никто не знает???
bloodman (2004-09-05 14:46:00) [14]Сделал так чтобы процесс пошел не с нулевого елемента , все равно просто удалился первый :((
bloodman (2004-09-05 14:37:00) [15]RightDB : TDBDinArray;
function Create(DB : TDBDinArray):boolean;
begin
...
Move(DB[I + 1], DB[I], ( Length(DB) - I) * SizeOf(DB[0]));
Setlength(DB, Length(DB) -1);
...
end;
вызываю так:
res:=Create(RightDB);
type
TDBRecord = record
ID : Integer;
Father : Integer;
Name : String[30];
Path : String[255];
Parameters : string[30];
Shortcut : string[30];
IconPath : String[255];
end;
type
TDBDinArray = array of TDBRecord;
Собственно херня ета происходит на move (или на for без разници) причем при первом вызове , то есть когда удаляется нулевой елемент потом все нормально идет- из rightdb ничего не удаляется.
begin...end (2004-09-05 14:33:00) [16]
> [11] bloodman © (05.09.04 14:27)
Что за RightDB? Где код?
bloodman (2004-09-05 14:27:00) [17]Что никто не знает ответа????
Почему удаляется у RigthDB первый элемент?? Остальные то остаются... ???
type
TDBDinArray = array of TDBRecord;
bloodman (2004-09-05 13:49:00) [18]блин бред какой то
For Z:=I to Length(DB) - 2 do DB[Z]:= DB[Z+1];
тоже удаляет первый элемент . Ж((
наверно даже не удаляет а сдвигает адрес первого элемента на размер записи :( ПОЧЕМУ ??? не понимаю там ведь даже удаления то нету...
bloodman (2004-09-05 13:39:00) [19]НЕТ не все. Этот код у меня не правильно работает! Вот функция:
function Create(DB : TDBDinArray):boolean;
begin
...
Move(DB[I + 1], DB[I], ( Length(DB) - I) * SizeOf(DB[0]));
Setlength(DB, Length(DB) -1);
...
end;
вызываю так:
res:=Create(RightDB);
А происходит вот что : При первом вызове этой функции(move) она удалает первый элемент не только в DB (лок переменная) но и в RightDB !! почему ??? Мне этого не нужно..
Erik1 (2004-09-02 12:00:00) [20]To bloodman
Ну ты даеш.
i := удаляемый элемет масива
Size := Length(DB);
Move(DB[i + 1], DB[i], (Size - i) * SizeOf(DB[0]));
Setlength(DB, Size-1);
И все.