Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.09.26;
Скачать: CL | DM;

Вниз

Есть ли функция для удаления 1 элемента из динамического масива?   Найти похожие ветки 

 
bloodman ©   (2004-09-01 19:54) [0]

Есть ли функция для удаления 1 элемента из динамического масиваб и последующим изменением его длины??
А то не хочется писать свою, наверняка же есть...


 
Семен Сорокин ©   (2004-09-01 20:06) [1]

есть для последнего SetLength(arr, Length(arr)-1), а еще есть Move.

PS.
 Используй TList или его наследников.


 
Romkin ©   (2004-09-01 20:51) [2]

TList на самом деле только растет :))
http://www.delphimaster.ru/articles/dyntable/index.html
Легко адаптировать под массив ;)


 
Fay ©   (2004-09-01 21:04) [3]

2 bloodman ©   (01.09.04 19:54)
Твой вопрос длиннее той функции, которую не хочется писать.


 
Endi   (2004-09-01 22:07) [4]

Я пользуюсь вот этой функцией.


procedure Delete(Idx:integer;M:array of integer); //Idx - индекс, с который нужно удалить
var
i:integer;
begin
for i:=Idx to Length(M)-2 do begin
M[i]:=M[i+1];
end;
SetLength(M,Length(M)-1);
end;


 
Palladin ©   (2004-09-01 22:12) [5]


> Endi   (01.09.04 22:07)

Почитай справку про Move, очень оптимизируешь свою функцию...


 
bloodman ©   (2004-09-01 22:22) [6]

Fay ©   (01.09.04 21:04) [3]
Да собственно я решил без функции обойтись:
For Z:=I to Length(DB) - 2 do DB[Z]:= DB[Z+1];
        SetLength(DB, Length(DB) - 1);

:)


 
Семен Сорокин ©   (2004-09-02 09:47) [7]


> Romkin ©   (01.09.04 20:51) [2]
> TList на самом деле только растет :))
> http://www.delphimaster.ru/articles/dyntable/index.html
> Легко адаптировать под массив ;)

Отличная статья.


 
Erik1   (2004-09-02 12:00) [8]

To bloodman
Ну ты даеш.
i := удаляемый элемет масива
Size := Length(DB);
Move(DB[i + 1], DB[i], (Size - i) * SizeOf(DB[0]));
Setlength(DB, Size-1);
И все.


 
bloodman ©   (2004-09-05 13:39) [9]

НЕТ не все. Этот код у меня не правильно работает! Вот функция:

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 !! почему ??? Мне этого не нужно..


 
bloodman ©   (2004-09-05 13:49) [10]

блин бред какой то
For Z:=I to Length(DB) - 2 do DB[Z]:= DB[Z+1];
тоже удаляет первый элемент . Ж((
 наверно даже не удаляет а сдвигает адрес первого элемента на размер записи :( ПОЧЕМУ ??? не понимаю там ведь даже удаления то нету...


 
bloodman ©   (2004-09-05 14:27) [11]

Что никто не знает ответа????
Почему удаляется у RigthDB первый элемент?? Остальные то остаются... ???

type
 TDBDinArray = array of TDBRecord;


 
begin...end ©   (2004-09-05 14:33) [12]


> [11] bloodman ©   (05.09.04 14:27)

Что за RightDB? Где код?


 
bloodman ©   (2004-09-05 14:37) [13]

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 ничего не удаляется.


 
bloodman ©   (2004-09-05 14:46) [14]

Сделал так чтобы процесс пошел не с нулевого елемента , все равно просто удалился первый :((


 
bloodman ©   (2004-09-05 21:49) [15]

что никто не знает???


 
Defunct ©   (2004-09-05 23:37) [16]

Там где часто приходится удалять. Лучше использовать динамический односвязный список, а не массив.

тогда удаление сводится к двум действиям:

- освобождение памяти
- выброс элемента из цепочки.

Возвращаясь к вашему вопросу. Удаление элемента из динамического массива - действие трудоемкое, но осуществимое.

Procedure Delete(var DynArray: TYoursDynamicArray; ItemIndex: Integer);
Var I:Integer;
Begin
 If ItemIndex< Length(DynArray) Then
 Begin
   For I:=ItemIndex+1 To Length(DynArray)-1 Do DynArray[i-1] := DynArray[i];
   SetLength(DynArray, Length(DynArray)-1);
 End;
End;


 
bloodman ©   (2004-09-05 23:47) [17]

Defunct ©   (05.09.04 23:37) [16]
Ваща процедура аналогична моей , даже больше , это одно и тоже .
Для чего это нужно было приводить не понятно. Вопрос был не в том КАК это сделать, а в том что почему-то удаляется элемент из основного масива, хотя не должен...

Односвязный список - это TList??


 
Defunct ©   (2004-09-06 00:11) [18]

> Для чего это нужно было приводить не понятно. Вопрос был не в том КАК это сделать, а в том что почему-то удаляется элемент из основного масива, хотя не должен...

Сюдя из Ваших постингов это понять нельзя, более того, вообще непонятно какое отношение имеет название функции "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 вставил, является он односвязным списком или нет, нужно смотреть по коду.


 
Erik1   (2004-09-06 10:04) [19]

Интересная у тебя функция Create(DB : TDBDinArray):boolean, вот бы еще узнать, что у тебя в I присваевается. :)
К томуже ненадо выкидавать переменую Size.


 
Romkin ©   (2004-09-06 11:58) [20]

Defunct ©  (06.09.04 00:11) [18] ТАк код TList посмотреть можно. И даже рекомендуется :)
Там фактически динамический массив, но только растет, не уменьшается. И, кстати, сделано весьма грамотно: это не dynamic array, а указатель на тип массив. Память же выделяется блоками, с запасом.
Вообще говоря, тип данных для хранения структуры выбирать надо строго исходя из тех действий, которые будут делаться. А абстрактных типов данных довольно много, выбор есть. Навскидку: массив, список (однонаправленный, двунаправленный, многосвязный), куча (двоичная, биномиальная...), двоичное дерево и тд :))


 
Erik1   (2004-09-06 13:35) [21]

To Romkin
Я думаю, что вот это "куча (двоичная, биномиальная...), двоичное дерево" автор за ругательство примет :)


 
bloodman ©   (2004-09-06 22:44) [22]

Defunct ©   (06.09.04 00:11) [18]
>>Ну и раз уж у вас получается непонятно что. То будьте добры не >>ходите вокруг да около с возгласами:
>>> Собственно херня ета происходит на move (или на for без >>разници) причем при первом вызове
>>А сформулируйте вопрос нормально. Что именно вы хотите сделать?
ок . Мне требуется передать в функцию динамический масив. В ней я постепенно удаляю все его элементы.Но мне нужно что бы этот масив остался в сохранности вне функции т.е. в ней нужно работать с его конией поэтому у меня в функции параметра VAR перед масивом нет. НО  все равно из него удаляется элемент при первом вызове процедуры move - это и есть моя проблема.


 
Defunct ©   (2004-09-06 23:13) [23]

> Мне требуется передать в функцию динамический масив. В ней я постепенно удаляю все его элементы.Но мне нужно что бы этот масив остался в сохранности вне функции т.е. в ней нужно работать с его конией поэтому у меня в функции параметра VAR перед масивом нет.

Стоп. Здесь противоречие, зачем удалять элементы так, чтобы ничего не удалялось? Где логика? Сформулируйте пожалуйста цель вашего, как бы это лучше выразиться, шаманства.

> НО  все равно из него удаляется элемент при первом вызове процедуры move - это и есть моя проблема.

Ответ на вопрос "почему удаляются элементы вне функции?" прост - динамический массив предствляет собой указатель на массив. Создайте копию массива внутри функции вручную, и работайте с ней.
Вопрос, зачем все это надо???


 
bloodman ©   (2004-09-07 20:23) [24]

>Создайте копию массива внутри функции вручную, и работайте с ней.
Это мне и нужно. Как лучше создать его копию.Я просто копирую элемент за элементом но ведь это медленно очень, пробовал с Copymem  не получилось.  

>Вопрос, зачем все это надо???
В процедуре я обрабатываю масив, чтобы не запоминать с какими жлементами я работал уже я их удаляю. Но потом вне этой функции я снова должен использовать этот масив. Вот поэтому мне нужна его копия внутри процедуры.


 
Defunct ©   (2004-09-07 20:40) [25]

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

Вот с этого надо было и начинать, т.е. ваша цель выполнить какие-то действия над данными однократно. Решается это добавлением дополнительного поля в структуру данных с именем скажем: 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  не получилось.

Да вы правы, это очень медленно. Особенно если много данных, то никто никогда не делает полное копирование.


 
Defunct ©   (2004-09-07 21:06) [26]

Конструктивный совет по улучшению вашей программы:

Откажитесь от 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;


 
bloodman ©   (2004-09-08 00:01) [27]

Спасибо за совет! Попробую сделать так.



Страницы: 1 вся ветка

Текущий архив: 2004.09.26;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.139 c
1-1094541629
KIR
2004-09-07 11:20
2004.09.26
Народ, кто уже работает с D8?


1-1095085977
Multy
2004-09-13 18:32
2004.09.26
Напомните как создаётся процедура перехватывающая все сообщения


3-1093791919
ghrup
2004-08-29 19:05
2004.09.26
Как сделать, чтобы TTable позволял редактировать запись, но не по


9-1085904941
MIX
2004-05-30 12:15
2004.09.26
OpenGL


3-1093240908
gunner
2004-08-23 10:01
2004.09.26
Post данных из DataSet в базу