Newsgroup: it.comp.lang.delphi
Titolo: Per specialisti Array

Avrei la necesità di eliminare gli indiciA e indiciB (di tipo integer) da un 
Array statico array[0..500]of integer
 
che deve per forza essere così per ragioni che non sto a descrivere.
 
Quando compilo il tutto con Delphi7Professional
 
mi dà errore: Incompatible types (ho letto su internet che dagli array 
statici non possono essere cancellati degli elementi).
 
Ecco il codice:
 
type
 
TMioArray = array[0..500] of Integer;
 
.....
 
procedure CancellaElementoArray(var Arr1: TMioArray; const IndiceA: 
Integer);///solo IndiceA per il momento
 
begin
 
Move(Arr1[IndiceA + 1], Arr1[IndiceA], SizeOf(Arr1[0]) * (Length(Arr1) - 
IndiceA - 1));
 
SetLength(Arr1, Length(Arr1) - 1); //errore
 
end;
 
Qualcuno mi può indicare il modo di eliminare comunque gli elementi?
 
Con la applicazione che stò creando stò lavorando con i Set di Delphi,ma 
devo per forza passare agli array
 
in quanto i set hanno un limite di 256 elementi e a me ne servono almeno 
500.
 
Su internet ho trovato una Unit che permette di emulare i Set con gli Array 
con tanto di funzioni tipo WordSetInclude,WordSetExclude
 
solo che manca la funzione di sottrazione degli indici.
 
Dovrei sostituire la stringa seguente che funziona solo con i Set
 
(TMioSET - [IndiceA] - [IndiceB])
 
con (TMioARRAY - [IndiceA] - [IndiceB])
 
quando compilo con TMioARRAY mi da errore:
 
Operator non applicable to this operand type(operatore -)
 
Qualcuno li può aiutare?
 
Ripeto lo array deve essere statico.
 
Grazie in ogni caso Luigi
 
Posto qui sotto la funzione trovata che a mio avviso credo più consona per 
una soluzione,
 
si dovrebbe togliere l'array S2 e giocare sugli indici A e B
 
function WordSetDifference(S1:TMioArray;S2:TMioArray):TMioArray;
 
{returns the difference of ArrayA(S1) over ArrayB(S2)}///commento dello 
autore della Unit(15 anni fa!) di cui però non ho lo indirizzo
 
var
 
i : integer;
 
begin
 
for i := Low(S1) to High(S1) do
 
Result[i] := S1[i] and not S2[i];///// Indici qui???
 
end;
 
?
 
 

 SetLength(Arr1, Length(Arr1) - 1); //errore
 
Non  vorrei dire una inesattezza, ma se il tuo array e' statico e ben 
definito (501 elementi) che bisogno hai di specificarne la lunghezza ??
SetLength lo usi quando NON conosci l'entita' dell'array e in runtime crei 
al volo l'array della lunghezza necessaria in quel momento, setlength e' per 
un array dinamico.
 
[quoto]
function WordSetDifference(S1:TMioArray;S2:TMioArray):TMioArray
 
{returns the difference of ArrayA(S1) over ArrayB(S2)}///commento dello
autore della Unit(15 anni fa!) di cui però non ho lo indirizzo
 
var
 
i : integer;
 
begin
 
for i := Low(S1) to High(S1) do
 
Result[i] := S1[i] and not S2[i];///// Indici qui???
 
end;
 
[fine]
 
Essendo due array statici sono ben definiti quindi puoi evitare di usare low 
e high ma 0 e 500.
Poi, onestamente, non ho capito cosa devi fare con questi integer.
Dato che l'integer accetta anche -1, puoi sempre usare (come soluzione 
sporca) il -1 come "cella" vuota.
Ovvero se devi cancellare l'indice 138 puoi sempre usare TMioArray[138]:=-1 
e quando leggi l'array (501 integer li leggi in meno di un attimo) salti 
tutti i -1 che trovi.
Un'altra strada e' quella che vede la traslazione dei valori dalla posizione 
da cancellare alla fine dell'array una cosa del tipo (cancellando la 138)
 
For I:=Posizione_da_cancellare to 500-1 do
begin
    TMayArray[I]:=TMayArray[I+1]
end
TMayArray[500]:=-1 // Eseendo l'ultima la imposti ad un valore che per te 
indica il nulla
 
Cosi' tiri in su tutti i valori di una posizione.
 
Spero di non aver creato confusione o dubbi aggiuntivi.
 
Ciao
 
Daniele
 

Ti ringrazio per la tua risposta,
 
purtroppo mi sono spiegato male postando delle funzioni che
 
hanno distorto la vera questione.
 
La pongo in modo molto semplice,perchè non hai prestato attenzione anche
 
alle altre funzioni che alla fine sono le solo due da confrontare:
 
?
 
?
 
Dovrei sostituire la stringa seguente che funziona solo con i Set
 
(TMioSET - [IndiceA] - [IndiceB])
 
con (TMioARRAY - [IndiceA] - [IndiceB])
 
quando compilo con TMioARRAY mi da errore:
 
Operator non applicable to this operand type(operatore -)
 
Ora la prima soluzione toglie da TMioSET contemporaneamente
 
i due indici A e B,vorrei che il tutto fosse possibile sostituendo
 
il tipo SET con un tipoARRAY.
 
Spero di essermi spiegato meglio
 
Grazie per una eventuale risposta.
 
Luigi
 
 

 ha scritto nel messaggio news:n5cf7g$ogu$1...@speranza.aioe.org...


 Qualcuno mi può indicare il modo di eliminare comunque gli elementi?
 
Qualcosa del genere
 
// Non compilato. Non testato.
procedure CancellaElementoArray(
  var Arr1: TMioArray; 
  var Lunghezza1: integer;
  const IndiceA: Integer);
begin
  Move(Arr1[IndiceA + 1], Arr1[IndiceA], 
    SizeOf(Arr1[0]) * (Length(Arr1) - IndiceA - 1));
  Lunghezza1 := Lunghezza1 -1 ;
end;
 
ciao
  Giacomo

Se ho ben capito, il problema è che dovresti fare l'operazione logica di 
esclusione (perfettamente supportata dai set, ma che non sono capienti 
quanto basta) usando un array, che non supporta l'operatore "-".
 
Se imponiamo come costraint al problema la size dell'array, allora non 
vedo altra soluzione che andare a scrivere Null nelle celle da 
"sottrarre" all'array originale.
 
Il side effect è che dovrai gestire il Null, riconoscendolo come 
indicatore di elemento da non trattare, infarcendo il tuo codice di una 
logica "cablata" e soggetta ad errori nel momento in cui cambierete la 
logica di trattare gli elementi cancellati.
 
-- 
Morde

 Array statico array[0..500]of integer
 
Sposta i tuoi elementi verso sinistra quando serve eliminare uno di essi, e decrementa una variabile "lunghezza" che tiene conto di quanti elementi ci sono nell'array. E` l'unico modo.

 Sposta i tuoi elementi verso sinistra [..] e decrementa una variabile "lunghezza" [...]
 
La tua soluzione potrebbe diminuire l'efficienza: spostare gli elementi 
a sinistra ad ogni cancellazione ha un certo peso computazionale.
Tuttavia, mantenere aggiornata una variabile con l'indirizzo dell'ultimo 
elemento, porterebbe a iterare su meno elementi.
Forse le due cose si compensano: più cancellazioni, meno elementi da 
iterare.
 
Lasciando stare la teoria e andando verso il caso pratico, io fare come 
ho suggerito: mettere un marker ad ogni elemento cancellato. E iterare 
sui cinquecento elementi ogni volta.
 
Stiamo comunque parlando di microsecondi...
 
-- 
Morde

 La tua soluzione potrebbe diminuire l'efficienza
 
Il problema e` nella struttura dati che ha scelto di usare: statica, con operazioni dinamiche. Usare un marker, come tu suggerisci, e` ancora meno efficiente. E` meglio eseguire una scrittura O(n) una volta, e poi letture O(1), che non applicare una tecnica O(n^2) come quella che suggerisci.

 Il problema e` nella struttura dati che ha scelto di usare: statica, con operazioni dinamiche. Usare un marker, come tu suggerisci, e` ancora meno efficiente. E` meglio eseguire una scrittura O(n) una volta, e poi letture O(1), che non applicare una tecnica O(n^2) come quella che suggerisci.
 
...sopratutto se, come mi aspetto, lui legge dalla struttura molte piu` volte di quante la modifica.
 

 con (TMioARRAY - [IndiceA] - [IndiceB])
In definitiva devi sottrarre [indice A] e [Indice B] dal tuo array.
Essendo un il tuo array STATICO di 501 "caselle" il cui valore e' un 
integer, e che essendo statico non lo puoi  >> variare << (questo lo devi 
sapere !!!!) , l'unica operazione a te concessa su quell'array e' quella di 
lavorare sul valore dell'integer.
Se per, convenzione, prendiamo -1 come valore che indica "cella vuota" 
allora puoi fare una cosa del genere (fatta al volo non testata e fatta da 
me!!! quindi super opinabile)
 
Procedure UpdateArray(MioArray : TMioArray; SubValue1, SubValue2 : Integer);
Var I : Integer;
Begin
    For I:=0 To 500 Do
    Begin
        If (MioArray[I]=SubValue1) Or (MioArray[I]=SubValue2) Then 
MioArray[I]:)-1
    End;
End;
 
Cosi' tutte le volte che nel tuo array si trova il valore da sottrarre al 
tuo array (SubValue1 o Subvalue2) in quella "cella" ci sara' il -1
Poi una volta riempito l'arrary con i vari -1, sta a te decidere cosa fare 
degli altri valori, ovvero puoi mettere tutti i -1 in cima o in fondo o 
lasciarli li.
Poi un altro aspetto che ho poco capito e' perche' se hai un array di 
integer devi andare a sottrarre delle stringhe.
Se i valori da sottrarre sono in formato stringa, allora li devi anche 
convertire in integer prima del confronto.
 
A mio avviso (e se lo dico io e' il  massimo per via della poca esperienza) 
grossi problemi non ci sono (leggendo anche le altre risposte).
Come primo aspetto le idee devono essere chiare.
 
Per esempio ti e' stato suggerito di mettere un marker al record cancellato 
(mantenendo il valore della cella) e questo lo si fa, per esempio con una 
cosa del tipo
 
MyRecord : Record
    Deleted : Boolean;
    Value    : Integer;
End;
 
TMyArray : Array [0..500] Of MyRecord
 
Quando Inizializzi
 
FillChar(TMyArray,SizeOf(TMyArray),#0) // imposti i boolean a false e gli 
integer a 0 (0 a -1 non ricordo)
 
Riempi il tuo array con i tuoi valori e nel ciclo
 
  If MyArray[I].Value = SubValue1 then MyArrary[I].Deleted:=True;
 
Cosi' hai il marker dello stato di ogni singola "cella" dell'array e il suo 
valore che lo puoi anche recuperare se cambi idea e non lo vuoi piu' 
cancellare.
 
Dato che sono solo 501 "celle" da controllare, anche una procedura poco 
performante come quella proposta sopra, se la devi leggere n volte sono 
istanti quasi impercettibili che non dovrebbero  inficiare la velocita' del 
programma.
 
Mi scuso per eventuali inesattezze e auguro buon Natale a tutti
 
Ciao
 
Daniele
 
 
 

Per il momento vi ringrazio tutti per le vostre gentili risposte,sto 
aspettando una risposta dallo ideatore
iniziale del programma che io ho poi modificato (turni nei tornei di 
scacchi)
č un programmatore olandese super esperto nel fare
software sui motori scacchistici che giocano tra di loro,qualche anno fa mi 
inviň i sorgenti fatti in Delphi7
del programma per formare i turni tra i giocatori,
ieri gli ho inviato il suo programma da me modificato(convertendo da Set ad 
Array)
Spero mi risponda al piů presto come ha fatto altre volte.
Nel frattempo cercherň di risolvere,aggiungo che tutte le operazioni che ho 
descritto sono comunque allo interno di una altra funzione tipo
if FunzioneMia(MioArray-IndiceA-IndiceB),TurnoCorrente+1 then begin.....
di tipo Boolean.
Se qualcuno vuole tentare di risolvere gli mando i sorgenti
ma dovrebbe essere un pň pratico di turni di scacchi,ma forse nemmeno.
Auguri di Buon Natale a tutti
Voltolini Luigi
 
 

 Usare un marker, come tu suggerisci, e` ancora meno efficiente.
 > E` meglio eseguire una scrittura O(n) una volta, e poi letture O(1),
 > che non applicare una tecnica O(n^2) come quella che suggerisci.
 
Non capisco da dove viene la tua ipotesi che la mia soluzione costi O(n^2).
Nel mio caso, un elemento da annullare verrebbe trovato in O(n) e 
scritto in O(1). Quindi per un'operazione di cancellazione avresti 
O(n)+O(1)=O(n)
 
Anche la tua soluzione ha complessità O(n), e questo perchè la ricerca 
su un array non può che essere sequenziale.
Nello specifico, per ogni cancellazione, tu devi prima cercare 
l'elemento da cancellare O(n), poi devi spostare tutti gli altri di una 
posizione che nel caso peggiore comporta un altro O(n).
 
Ricerca elemento: O(n)
Spostamento a destra dei successivi: O(1) per leggere + O(1) per 
scrivere = O(2), iterato per tutti gli elementi tranne il primo = O(n-1)
 
Alla fine una cancellazione costa O(n) + O(n-1) = O(2n-1) = O(n)
 
Però, volendo essere precisi, tu in questo modo riduci anche la 
dimensione degli elementi da iterare man mano che crescono le 
cancellazioni. Quindi se gli elementi cancellati sono la metà di quelli 
in origine, la complessità allora sarebbe un interessante O(n/2).
 
Mi rendo tuttavia conto che stiamo usando la notazione asintotica, ma 
dato che n=501, per quantità simili i tempi di accesso sono talmente 
bassi da essere trascurabili.
 
 
-- 
Morde

 posizione che nel caso peggiore comporta un altro O(n).
 
Niente affatto. Se vuoi cancellare l'elemento con indice 5, sposti semplicemente da 6 in poi. L'accesso all'elemento 6 e` O(1).
 
Senza ricorrere a calcoli di complessita`, e` facile capire che il mio algoritmo e` il migliore, se accedi molte piu` volte in scrittura di quante accedi il lettura.

 Senza ricorrere a calcoli di complessita`, e` facile capire che il mio algoritmo e` il migliore, se accedi molte piu` volte in scrittura di quante accedi il lettura.
 
Errata Corrige: "se accedi molte piu` volte in lettura".