2012-12-01 8 views
10

Ho 3 matrici, ad esempio:Confrontando gli array in Delphi

const 
    A: Array[0..9] of Byte = ($00, $01, $AA, $A1, $BB, $B1, $B2, $B3, $B4, $FF); 
    B: Array[0..2] of Byte = ($A1, $BB, $B1); 
    C: Array[0..2] of Byte = ($00, $BB, $FF); 

C'è un modo per confrontare e ottenere l'indice di quella giusta, invece di controllare ogni byte 1 da 1? Ad esempio:

function GetArrayIndex(Source, Value: Array of Byte): Integer; 
begin 
.. 
end; 

GetArrayIndex(A, B); // results 3 
GetArrayIndex(A, C); // results -1 

Grazie in anticipo.

+4

Ecco la risposta, [Esiste una funzione "Pos" per trovare i byte?] (Http://stackoverflow.com/q/4959566/576719). –

+0

Ottima e veloce risposta. (ho passato circa 1h e mezzo a non trovare nulla mentre lo facevi in ​​..5 '?). Grazie! Devo studiare un po 'di più sui puntatori e simili al fine di utilizzare tali funzioni. –

+0

Pubblicherò una versione rielaborata della risposta di Andreas per voi da studiare. –

risposta

12
function ByteArrayPos(const SearchArr : array of byte; const CompArr : array of byte) : integer; 
// result=Position or -1 if not found 
var 
    Comp,Search : AnsiString; 
begin 
    SetString(Comp, PAnsiChar(@CompArr[0]), Length(CompArr)); 
    SetString(Search, PAnsiChar(@SearchArr[0]), Length(SearchArr)); 
    Result := Pos(Search,Comp) - 1; 
end; 
+1

Fantastico! Esattamente quello che stavo cercando. –

+0

Mi chiedo se la tua risposta è sì o no. Voglio dire, 'Pos' esegue un * controllo di ogni byte 1 per 1 *? –

+0

Sì e No, ovviamente dovunque si deve fare un controllo byte per byte, ma non c'è bisogno di essere reimplementato. – bummi

7

Ecco una versione rielaborata di Andreas risposta here.

function BytePos(const Pattern: array of byte; const Buffer : array of byte): Integer; 
var 
    PatternLength,BufLength: cardinal; 
    i,j: cardinal; 
    OK: boolean; 
begin 
    Result := -1; 
    PatternLength := Length(Pattern); 
    BufLength := Length(Buffer); 
    if (PatternLength > BufLength) then 
    Exit; 
    if (PatternLength = 0) then 
    Exit; 
    for i := 0 to BufLength - PatternLength do 
    if Buffer[i] = Pattern[0] then 
    begin 
     OK := true; 
     for j := 1 to PatternLength - 1 do 
     if Buffer[i + j] <> Pattern[j] then 
     begin 
      OK := false; 
      Break; 
     end; 
     if OK then 
     Exit(i); 
    end; 
end; 

begin 
    WriteLn(BytePos(B,A)); // 3 
    WriteLn(BytePos(C,A)); // -1 
    ReadLn; 
end. 

La risposta di Bummis è preferire, comunque. Molto meglio.


Solo un'osservazione come indicato nei commenti.

Per dataset di piccole dimensioni BytePos supera le prestazioni ByteArrayPos, mentre per set di dati di grandi dimensioni (10000 articoli) la prestazione viene invertita.

Questo è per la modalità a 32 bit, in cui la funzione di sistema Pos() ottimizzata per l'assemblatore funziona al meglio per dataset di grandi dimensioni.

Nella modalità 64-bit, tuttavia, non esiste una funzione Pos() ottimizzata per l'assembler. Nel mio test di benchmark, BytePos è 4-6 volte più veloce di ByteArrayPos, per tutti i tipi di dimensioni del set di dati.


Aggiornamento

Il test di benchmark è stato fatto con XE3.

Durante il test ho scoperto un loop purepascal imperfetto nella funzione System.pas Pos().

È stata aggiunta una richiesta di miglioramento, QC111103, in cui la funzione proposta è circa 3 volte più veloce.

Ho ottimizzato anche il precedente BytePos e lo presentiamo qui sotto come ByteposEx().

function BytePosEx(const Pattern,Buffer : array of byte; offset : Integer = 0): Integer; 
var 
    LoopMax : Integer; 
    OK   : Boolean; 
    patternP : PByte; 
    patStart : Byte; 
    i,j  : NativeUInt; 
begin 
    LoopMax := High(Buffer) - High(Pattern); 
    if (offset <= LoopMax) and 
    (High(Pattern) >= 0) and 
    (offset >= 0) then 
    begin 
    patternP := @Pattern[0]; 
    patStart := patternP^; 
    for i := NativeUInt(@Buffer[offset]) to NativeUInt(@Buffer[LoopMax]) do 
    begin 
     if (PByte(i)^ = patStart) then 
     begin 
     OK := true; 
     for j := 1 to High(Pattern) do 
      if (PByte(i+j)^ <> patternP[j]) then 
      begin 
      OK := false; 
      Break; 
      end; 
     if OK then 
      Exit(i-NativeUInt(@Buffer[0])); 
     end; 
    end; 
    end; 
    Result := -1; 
end; 
+0

Sì, posso capire la tua funzione rielaborata in modo più semplice dell'originale. Grazie mille per il tuo impegno. –

+1

Non è facile da leggere come l'implementazione di Bummi, ma in teoria potrebbe essere molto più veloce perché non copia i dati. Quindi +1 anche per questo. Potrebbe fare la differenza se viene usato spesso o su grandi set di dati. Non ho effettivamente misurato la differenza però. –

+0

@WoutervanNifterick, ho eseguito un benchmark su un piccolo set di dati (quello sopra) e un set di dati di grandi dimensioni (10000 elementi). Per un hit alla fine, 'BytePos' è un po 'più di 3 volte più veloce nel dataset piccolo, mentre per il set di dati di grandi dimensioni il risultato è il contrario. Conclusione: l'allocazione delle due stringhe in 'ByteArrayPos' darà una penalizzazione delle prestazioni per i piccoli set di dati, mentre la funzione di sistema ottimizzata' Pos' eccelle per i set di dati di grandi dimensioni. –