2012-12-01 89 views
10

我有3個陣列,例如:比較陣列在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); 

有沒有辦法進行比較,並得到正確的索引,而不是檢查由1每個字節1?例如:

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

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

在此先感謝您。

+4

這裏是答案,[是否有任何「Pos」函數來查找字節?](http://stackoverflow.com/q/4959566/576719)。 –

+0

偉大而快速的回覆。 (我花了大約1小時半在沒有做任何事的時候找不到任何東西)。謝謝!爲了利用這些功能,我必須研究更多關於指針等的內容。 –

+0

我會發佈一個安德烈亞斯答案的重做版本供你學習。 –

回答

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

太棒了!正是我在找什麼。 –

+0

我不知道你的答案是肯定的或不是。我的意思是,'Pos'是否對每個字節1 *進行*檢查? –

+0

是和否,當然somwhere必須逐字節地進行校驗,但不需要重新實現。 – bummi

7

這是Andreas的返工版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. 

Bummis答案是寧願,雖然。好多了。


正如在評論中所指出的一句話。

對於小型數據集BytePos優於ByteArrayPos,而對於大型數據集(10000個項目),性能會反轉。

這是針對32位模式,其中彙編程序優化Pos()系統函數對於大型數據集最適合。

儘管在64位模式下沒有彙編器優化的Pos()函數。 在我的基準測試中,對於所有類型的數據集大小,BytePosByteArrayPos快4-6倍。


更新

基準測試與XE3製作。

在測試過程中,我在System.pas函數Pos()中發現了一個有缺陷的purepascal循環。

已添加改進請求QC111103,其中所提議的功能快大約3倍。

我還優化了上面的BytePos,並在下面以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

是的,我可以理解你的返工功能比原來更容易。非常感謝你的努力。 –

+1

它不像Bummi的實現那樣容易閱讀,但理論上這可能會更快,因爲它不復制數據。因此,這個也是+1。如果經常使用或在大型數據集上使用,它可能會有所不同。雖然我沒有真正衡量差異。 –

+0

@WoutervanNifterick,我在一個小數據集(上面的那個)和一個大數據集(10000個元素)上做了一個基準測試。最後的結果是,在小數據集中'BytePos'的速度略快3倍,而對於大數據集,結果則相反。結論:在'ByteArrayPos'中分配兩個字符串將會給小數據集帶來性能損失,而優化的'Pos'系統函數會勝過大數據集。 –