2012-12-01 90 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'系统函数会胜过大数据集。 –