Newsgroup: it.comp.lang.delphi
Titolo: [LUNGO] Estrarre un elemento da array bidimensionale e ricompattare array. Dubbio su Move.

Sto cercando il modo migliore per eliminare un elemento qualsiasi da un 
array dinamico e poi ricompattare l'array.
Esempio, dato:
  0 1 2 3 4 5
volendo togliere l'elemento di indice 2, devo far scorrere tutto l'array a 
sinistra a partire dall'elemento di indice 3
  0 1 3 4 5 X
poi sistemo la lunghezza e ottengo
 0 1 3 4 5
Con gli array monodimensionali (vettori), uso il codice della procedura 
Delete qui sotto(lo stesso sistema utilizzato in TList).
[Per provarlo, basta piazzare un Button su una form e collegare l'evento 
OnClick]
Il dubbio che ho -perň- č con gli array bidimensionali (vedi piů sotto).
/////////////////////////////////////////////////////////////////
type
  TIntegerArray = array of Integer;
function Init(const Count: Integer): TIntegerArray;
var
  i: Integer;
begin
  SetLength(Result, Count);
  for i:= 0 to Pred(Count) do
    Result[i]:= i
end;
procedure Delete(const Index: Integer; var AnArray: TIntegerArray);
var
  Size: Integer;
begin
  Size:= SizeOf(Integer) * (High(AnArray) - Index);
  Move(AnArray[Succ(Index)], AnArray[Index], Size);
  SetLength(AnArray, High(AnArray));
end;
procedure ShowItems(AnArray: TIntegerArray);
var
  i: Integer;
  s: string;
begin
  s:= '';
  for i:= 0 to High(AnArray) do
    s:= s + IntToStr(AnArray[i]) + #9;
  ShowMessage(TrimRight(s));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  Vector: TIntegerArray;
begin
  Vector:= Init(6);
  ShowItems(Vector);
  Delete(2, Vector);
  ShowItems(Vector);
end;
//////////////////////////////////////////////////////////////
Con gli array bidimensionali invece di cancellare un elemento, vorrei 
cancellare una riga intera e compattare l'array (piů o meno come visto 
sopra).
Il codice qua sotto sembra funzionate [anche qui per farlo funzionare 
basta piazzare un Button su una form e collegare l'OnClick], ma non sono 
affatto sicuro che funzioni sempre in maniera corretta.
Mi riferisco a ciň che avviene nella procedura Delete_Q: infatti muovendo 
("scrollando") tutte le righe dell'array per andare a riempire il buco 
lasciato da quella eliminata, dň per scontato che l'array sia allocato in 
memoria come una sequenza ordinata del tipo <riga0><riga1><riga2> etc.
In altre parole, siccome sto lavorando su un array bidimensionale, in 
realtŕ ho "un array di puntatori ad array", perň nessuno mi assicura che 
questi ultimi array siano allocati in memoria in maniera sequenziale, in 
modo che la procedura Move dia il risultato atteso.
Prima di passare alle alternative (per esempio creare un nuovo array 
destinazione e copiare solo le righe che m'interessano con la funzione 
Slice), volevo sapere che ne pensate voi.
/////////////////////////////////////////////////////////////
type
//  TIntegerArray = array of Integer;    //vedi sopra
  T2DIntArray = array of TIntegerArray;
function Init_Q(const Count: Integer): T2DIntArray;
var
  r, c, i: Integer;
begin
  i:= 0;
  SetLength(Result, Count, Count);
  for r:= 0 to Pred(Count) do
    for c:= 0 to Pred(Count) do
    begin
      Result[r][c]:= i;
      Inc(i);
    end;
end;
procedure Delete_Q(const Index: Integer; var AnArray: T2DIntArray);
var
  Size: Integer;
begin
  Size:= (SizeOf(TIntegerArray) * (High(AnArray) - Index));
  AnArray[Index]:= nil;
  Move(AnArray[Succ(Index)], AnArray[Index], Size);
  SetLength(AnArray, High(AnArray), Length(AnArray));
end;
procedure ShowItems_Q(AnArray: T2DIntArray);
var
  r, c: Integer;
  s: string;
begin
  s:= '';
  for r:= 0 to High(AnArray) do
  begin
    for c:= 0 to High(AnArray[r]) do
      s:= s + IntToStr(AnArray[r][c]) + #9;
    s:= TrimRight(s) + #13#10;
  end;
  ShowMessage(s);
end;
//procedure TForm1.Button2Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var
  Quad: T2DIntArray;
begin
  Quad:= Init_Q(5);
  ShowItems_Q(Quad);
  Delete_Q(2, Quad);
  ShowItems_Q(Quad);
end;
////////////////////////////////////////////////////////////////
-- 
Mauro Falzari 
   [ 
http://digilander.libero.it/mauro.falzari
 ]
 
 "Se guardi nell'abisso, anche l'abisso guarda in te." 
   (Friedrich Nietzsche)

 Slice), volevo sapere che ne pensate voi.
parte della tesi che sto svolgengo riguarda proprio l'attenzione nella
memorizzazione di una matrice; sei sicuro di non poter allocale, al posto di
una matrice (array bidimensionale) un vettore (array unidimensionale)? ti
consiglierei, nel caso scegliessi questa strada di memorizzarlo per righe
(nei primi n elem, nxn è la dim della matrice, ci metti la prima riga,
dall'elem n+1 fino a 2n la segonda riga e così via) in modo che, quando devi
eliminare una riga puoi utilizzare nuovamente le procedure di 'move' che
applicavi su un vettore.
Naturalmente, il modo di indicizzare la matrice in un vettore cambia: per
accedere all'elemento a[i,j] devi calcolarti l'indirizzo nel vettore come
n*i+j(+1 se parti da 1...)
Spero di essere stato abbastanza chiaro (vista l'ora e la malattia
galoppante); se hai altre domande, falle pure
ciao

[errata corrige]
procedure Delete(const Index: Integer; var AnArray: TIntegerArray);
var
  Size: Integer;
begin
  Size:= SizeOf(Integer) * (High(AnArray) - Index);
  if Index < High(AnArray) then
    Move(AnArray[Succ(Index)], AnArray[Index], Size);
  SetLength(AnArray, High(AnArray));
end;
//...
procedure Delete_Q(const Index: Integer; var AnArray: T2DIntArray);
var
  Size: Integer;
begin
  Size:= (SizeOf(TIntegerArray) * (High(AnArray) - Index));
  AnArray[Index]:= nil;
  if Index < High(AnArray) then
    Move(AnArray[Succ(Index)], AnArray[Index], Size);
  SetLength(AnArray, High(AnArray), Length(AnArray[0]));
end;


 galoppante); se hai altre domande, falle pure
ah ho capito cosa fai: tu "appiattisci" la matrice in un vettore mettendo 
tutto di fila, in questo modo la Move verrebbe applicata in maniera 
assolutamente "sicura". Però così mi perderei tutte le ottimizzazioni del 
compilatore sugli array (cmq penso che quello che tu mi suggerisci sia 
proprio il modo in cui il gestore di memoria manipola gli array).
Tra l'altro avevo fatto degli esperimenti (funzionanti) con una TList di 
TList e ho notato una grande differenza nelle prestazioni (per esempio già 
nella creazione di una matrice di 8000x8000 le TList ci mettono molto ma 
molto più tempo degli array: sul mio pc qualcosa come 10-12 secondi a 2 
secondi).
In ogni caso, il sistema che ho descritto nel post iniziale (con le 
correzioni) non sembra dare problemi.


 correzioni) non sembra dare problemi.
buon pro! se hai tempo e vuoi provare a implementare il metodo che ti
dicevo... ;)
ciao

Il mio lo scopo ultimo era quello di avere una procedura tale che, data 
una matrice quadrata del tipo
  101 102 103 104
  201 202 203 204
  301 302 303 304
  401 402 403 404
mi eliminasse tutta la riga e tutta la colonna aventi l'indice dato 
(esempio: 1; nota che è un indice 0-based)
  101 |102| 103 104
  ----+---+--------
  201 |202| 203 204
  ----+---+--------
  301 |302| 303 304
      |   |
  401 |402| 403 404
così da ottenere
  101 103 104  
  301 303 304
  401 403 404
Alla fine ho mantenuto la Delete precedente (quella sull'array 
monodimensionale) e ho deciso di lasciar perdere la Move sull'array 
bidimensionale, a favore della strada più sicura dei cicli for.
Se a qualcuno magari interessa, qui c'è il codice dell'esempio funzionante 
e definitivo (sempre se non mi arrivano suggerimenti per ulteriori 
migliorie).
[Inserire il codice nella sezione implementation di una form con un Button 
e collegare l'OnClick]
type
  TIntegerArray = array of Integer;
  T2DIntArray = array of TIntegerArray;
function Init(const Count: Integer): T2DIntArray;
var
  r, c: Integer;
begin
  SetLength(Result, Count, Count);
  for r:= 0 to Pred(Count) do
    for c:= 0 to Pred(Count) do
      Result[r][c]:= StrToInt(IntToStr(Succ(r)) + '0' + IntToStr(Succ(c)))
end;
procedure Delete(const Index: Integer; var AnArray: TIntegerArray);
var
  Size: Integer;
begin
  Size:= SizeOf(Integer) * (High(AnArray) - Index);
  if Index < High(AnArray) then
    Move(AnArray[Succ(Index)], AnArray[Index], Size);
  SetLength(AnArray, High(AnArray));
end;
procedure DeleteEntry(const Index: Integer; var AnArray: T2DIntArray);
var
  tmp: T2DIntArray;
  k, NewLength: Integer;
begin
  NewLength:= High(AnArray);
  SetLength(tmp, NewLength, NewLength);
  for k:= 0 to Pred(Index) do
  begin
    Delete(Index, AnArray[k]);
    tmp[k]:= AnArray[k];
  end;
  for k:= Succ(Index) to High(AnArray) do
  begin
    Delete(Index, AnArray[k]);
    tmp[k - 1]:= AnArray[k];
  end;
  AnArray:= tmp;
end;
procedure ShowItems(AnArray: T2DIntArray);
var
  r, c: Integer;
  s: string;
begin
  s:= '';
  for r:= 0 to High(AnArray) do
  begin
    for c:= 0 to High(AnArray[r]) do
      s:= s + IntToStr(AnArray[r][c]) + #9;
    s:= TrimRight(s) + #13#10;
  end;
  if s = EmptyStr then
    s:= '(vuoto)';
  ShowMessage(s);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  Quad: T2DIntArray;
begin
  Quad:= Init(4);
  ShowItems(Quad);
  DeleteEntry(1, Quad);
  ShowItems(Quad);
  DeleteEntry(2, Quad);
  ShowItems(Quad);
  DeleteEntry(1, Quad);
  ShowItems(Quad);
  DeleteEntry(0, Quad);
  ShowItems(Quad);
end;


 discuterne...
ho calcolato che una matrice 8000x8000 fatta con TList di TList alloca al 
momento della creazione qualcosa come 1.07e12 puntatori!!


 momento della creazione qualcosa come 1.07e12 puntatori!!
discutiamone, allora.... ;)

Mauro Falzari ha scritto:
...
Care vecchie liste fatte con puntatori e allocazione/deallocazione manuale
e gestione di matrice fatta con lista 
Tlista record of
successore,predecessore: ^ Tlista;
valore: cosa ti serve;
..
end;
(sintassi da verificare !!!)
secondo me č il sistema piu veloce e compatto che si possa utilizzare.
Ciao
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 e gestione di matrice fatta con lista 
proprio in "old school style" eh :-)


 discutiamone, allora.... ;)
a proposito..buona guarigione!


 proprio in "old school style" eh :-)
ma in questo caso (sopratutto se hai matrici sparse non hai altra scelta)!!
Ciao
Marco
old lo sono io !
