2010-11-04 20 views
6

Ho un algoritmo di calcolo in Delphi con un numero di opzioni diverse, e ho bisogno di provare ogni combinazione di opzioni per trovare una soluzione ottimale.Enumera i valori impostati possibili in Delphi

TMyOption = (option1, option2, option3, option4); 
TMyOptions = set of TMyOption; 

mi chiesi sull'utilizzo di un ciclo intero di enumerarli:

for EnumerationInteger := 0 to 15 do begin 
    Options := TMyOptions(EnumerationInteger); 
end; 

Questo non può essere compilato. Quello che mi chiedevo era se esistesse un metodo abbastanza semplice per convertire da Integer a Set (la maggior parte delle domande sul Web provano ad andare dall'altra parte, da Set a Integer) e, in caso affermativo, di cosa si tratta?

Un'altra possibilità è quella di utilizzare solo l'intero come un campo di bit: l'adesione

C_Option1 = 1; 
C_Option2 = 2; 
C_Option3 = 4; 
C_Option4 = 8; 

e poi prova con un bit a bit e:

if (Options and C_Option2) > 0 then begin 
    ... 
end; 

Ho provato questo, e funziona , ma sembra che lavorare con gli insiemi sia più naturale e utilizzare meglio il sistema dei tipi (anche se sto andando fuori dal suddetto sistema di tipi per enumerare gli insiemi).

Esiste un modo migliore/più sicuro per enumerare tutte le possibili combinazioni di set rispetto all'enumerazione della rappresentazione intera sottostante?

Note:

  1. so che i valori interi di un insieme non sono garantiti in teoria (anche se ho il sospetto che siano in pratica se non si gioca con la numerazione di enumerazione).
  2. Ci potrebbero essere più di quattro opzioni (sì, lo so che cresce in modo esponenziale e se ci sono troppe opzioni che l'algoritmo potrebbe richiedere per sempre).

risposta

4

Prova

var EnumerationByte: Byte; 
... 
for EnumerationByte := 0 to 15 do begin 
    Options := TMyOptions(EnumerationByte); 
end; 
+0

che effettivamente funziona. Presumo che non funzionerebbe per i set con più di 8 membri? (anche se a quel punto l'algoritmo è probabilmente già troppo lento). –

+1

Do sizeof (SetVar) per scoprire come un particolare set è rappresentato da Delphi. –

2

il codice non compilato perché il vostro enumerazione (TMyOption) ha meno di 8 valori, e Delphi utilizzano la dimensione minima possibile (in byte) per i set. Quindi, una variabile di byte funzionerà per te.

Se si dispone di un set con più di 8 ma meno di 16 elementi possibili, una Word funzionerà (e non un numero intero).

Per più di 16 ma meno di 32 una variabile DWord e typecast.

Per più di 32 elementi possibili, penso che un approccio migliore sia utilizzare una serie di byte o qualcosa del genere.

+1

Il problema non è la dimensione del numero intero, il problema è che sta provando a trasmettere al tipo * set * (TMyOptions), non al tipo enumerato. –

+0

Alberto: il cast impostato su byte-word-dword type è ovviamente possibile e significativo in questo caso. – jachguate

0

Il problema è che si sta tentando di eseguire il cast sul tipo set anziché sul tipo enumerato. È possibile eseguire il cast tra intero ed enumerato perché entrambi sono tipi ordinali, ma non è possibile eseguire il cast su un set perché utilizzano bitfiels come già notato. Se si utilizza:

for EnumerationInteger := 0 to 15 do begin 
    Option := TMyOption(EnumerationInteger); 
end; 

funzionerebbe, anche se non è quello che si desidera.

Ho avuto questo stesso problema alcuni mesi fa e sono giunto alla conclusione che non è possibile enumerare il contenuto di un set in Delphi (almeno in Delphi 7) perché la lingua non definisce tale operazione su un set .

Modifica: Sembra che sia possibile anche in D7, vedere i commenti a questa risposta.

+0

Vedere la risposta accettata. Utilizzare un byte invece di un intero funziona. –

+1

erm ... È possibile elencare il contenuto di un set. È solo contro-intuitivo. Ad esempio: I: = Basso (Enum) a alto (Enum) do /// se I in Set allora. –

+2

Oppure, a partire da Delphi 2005, è possibile enumerare direttamente il contenuto: 'per el in s do ...' –

0

500 - La risposta dell'errore del server interno è probabilmente la più semplice.

Un altro approccio che avrebbe meno probabilità di rompere con le modifiche al numero di opzioni sarebbe quello di dichiarare un array di valori booleani e attivarli/disattivarli. Questo è più lento di lavorare con gli interi puri però. Il vantaggio principale, non è necessario modificare il tipo intero che si utilizza e si può usare se si dispone di più di 32 opzioni.

procedure DoSomething 
var BoolFlags : Array[TOption] of Boolean; 
    I: TOption; 
    function GetNextFlagSet(var Bools : Array of Boolean) : Boolean; 
    var idx, I : Integer; 
    begin 
    idx := 0; 
    while Bools[idx] and (idx <= High(Bools)) do Inc(idx); 

    Result := idx <= High(Bools); 

    if Result then 
     for I := 0 to idx do 
     Bools[I] := not Bools[I]; 
    end; 
begin 
    for I := Low(BoolFlags) to High(BoolFlags) do BoolFlags[i] := False; 

    repeat 
    if BoolFlags[Option1] then 
     [...] 

    until not GetNextFlagSet(BoolFlags); 
end; 
0

Casting da un intero in un set non è possibile, ma Tondrej una volta ha scritto un blog article su SetToString e StringToSet che espone ciò che si desidera nel metodo SetOrdValue:

uses 
    TypInfo; 

procedure SetOrdValue(Info: PTypeInfo; var SetParam; Value: Integer); 
begin 
    case GetTypeData(Info)^.OrdType of 
    otSByte, otUByte: 
     Byte(SetParam) := Value; 
    otSWord, otUWord: 
     Word(SetParam) := Value; 
    otSLong, otULong: 
     Integer(SetParam) := Value; 
    end; 
end; 

Il codice poi sarebbe diventato questo:

for EnumerationInteger := 0 to 15 do begin 
    SetOrdValue(TypeInfo(TMyOptions), Options, EnumerationInteger); 
end; 

--jeroen

6

So che questa domanda è abbastanza vecchio, ma questo è la mia preferenza in quanto è semplice e naturale per me:

function NumericToMyOptions(n: integer): TMyOptions; 
var 
    Op: TMyOption; 
begin 
    Result:= []; 
    for Op:= Low(TMyOption) to High(TMyOption) do 
    if n and (1 shl ord(Op)) > 0 then Include(Result, Op); 
end; 
+0

Molto bello, lo rende molto più ordinato (anche se potrei restare con l'altro solo perché è più veloce). –

Problemi correlati