Сравнение массива байтов на С#

У меня есть два байтовых массива в С# с использованием .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);
}

ССЫЛКА