Сравнение массивов в Delphi
У меня есть 3 массива, например:
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
Спасибо заранее.
Ответы
Ответ 1
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;
Ответ 2
Вот переработанная версия Андреаса отвечает здесь.
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.
В то же время ответ Бэмми предпочитает. Гораздо лучше.
Просто замечание, как отмечено в комментариях.
Для небольших наборов данных BytePos
превосходит ByteArrayPos
, тогда как для больших наборов данных (10000 элементов) производительность меняется на противоположную.
Это для 32-разрядного режима, где оптимизированная ассемблером системная функция Pos()
работает в лучшем случае для больших наборов данных.
Однако в 64-битном режиме функция Pos() не оптимизирована ассемблером.
В моем тестовом тесте BytePos
в 4-6 раз быстрее, чем ByteArrayPos
, для всех типов размеров набора данных.
Обновление
Тест-тест был выполнен с помощью XE3.
Во время теста я обнаружил ошибочный цикл purepascal
в функции System.pas Pos()
.
Добавлен запрос на улучшение, 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;