Сравнение массива байтов на С#
У меня есть два байтовых массива в С# с использованием .NET 3.0.
Что такое "самый эффективный" способ сравнить, содержат ли два байтовых массива одно и то же содержимое для каждого элемента?
Например, массив байтов {0x1, 0x2}
совпадает с {0x1, 0x2}
. Но массив байтов {0x1, 0x2}
и массив байтов {0x2, 0x1}
не совпадают.
Ответы
Ответ 1
Ну, вы могли бы использовать:
public static bool ByteArraysEqual(byte[] b1, byte[] b2)
{
if (b1 == b2) return true;
if (b1 == null || b2 == null) return false;
if (b1.Length != b2.Length) return false;
for (int i=0; i < b1.Length; i++)
{
if (b1[i] != b2[i]) return false;
}
return true;
}
(Я обычно использую фигурные скобки для всего, но я думал, что экспериментирую с этим стилем макета только для изменения...)
У этого есть несколько оптимизаций, которые SequenceEqual
не может (или не работает) выполнять, например, проверку длины переднего конца. Прямой доступ к массиву также будет немного более эффективным, чем использование счетчика.
По общему признанию, это вряд ли может существенно повлиять на большинство случаев...
Вы можете сделать это быстрее в неуправляемом коде, заставив его сравнивать 32 или 64 бита за раз, а не 8, но я бы не хотел кодировать это на лету.
Ответ 2
Вы можете использовать метод SequenceEqual
:
bool areEqual = firstArray.SequenceEqual(secondArray);
Как указано в комментариях, SequenceEqual
требует .NET 3.5 (или LINQBridge, если вы используете VS2008 и нацеливаете на более ранний версия рамки).
Ответ 3
Джон упомянул о сравнении нескольких байтов одновременно с использованием небезопасного кода, поэтому мне пришлось отпустить его:
public unsafe bool ByteArraysEqual(byte[] b1, byte[] b2) {
if (b1 == b2) return true;
if (b1 == null || b2 == null) return false;
if (b1.Length != b2.Length) return false;
int len = b1.Length;
fixed (byte* p1 = b1, p2 = b2) {
int* i1 = (int*)p1;
int* i2 = (int*)p2;
while (len >= 4) {
if (*i1 != *i2) return false;
i1++;
i2++;
len -= 4;
}
byte* c1 = (byte*)i1;
byte* c2 = (byte*)i2;
while (len > 0) {
if (*c1 != *c2) return false;
c1++;
c2++;
len--;
}
}
return true;
}
Безопасный код становится довольно оптимизированным (компилятор знает, что ему не нужно проверять границы индекса, например), поэтому я не ожидал бы, что небезопасный код будет намного быстрее. Любая существенная разница может возникнуть из способности сравнивать сразу несколько байтов.
Ответ 4
Если вы хотите, чтобы это было очень быстро, вы можете использовать небезопасный код (что не всегда возможно):
public static bool ArraysEqual(byte[] b1, byte[] b2)
{
unsafe
{
if (b1.Length != b2.Length)
return false;
int n = b1.Length;
fixed (byte *p1 = b1, p2 = b2)
{
byte *ptr1 = p1;
byte *ptr2 = p2;
while (n-- > 0)
{
if (*ptr1++ != *ptr2++)
return false;
}
}
return true;
}
}
Ответ 5
Если вы не слишком обеспокоены производительностью, вы можете рассмотреть IStructuralEquatable
.
.NET Framework Поддерживается в версиях: 4.5, 4
Структурное равенство означает, что два объекта равны, потому что они имеют равные значения. Он отличается от ссылочного равенства.
Пример:
static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
IStructuralEquatable eqa1 = a1;
return eqa1.Equals(a2, StructuralComparisons.StructuralEqualityComparer);
}
ССЫЛКА