2009-09-07 4 views
11

У меня есть два байтовых массива в C# с использованием .NET 3.0.C# байт сравнения массива

Что такое «самый эффективный» способ сравнить, содержат ли два байтовых массива одно и то же содержимое для каждого элемента?

Например, массив байтов {0x1, 0x2} такой же, как {0x1, 0x2}. Но байт-массив {0x1, 0x2} и байтовый массив {0x2, 0x1} не совпадают.

+2

Дубликат http://stackoverflow.com/questions/43289/ – Hafthor

ответ

32

Ну, вы могли бы использовать:

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 - но я не хотел бы кодировать это на лету.

+0

Мне нравится ваше решение! – George2

+0

Привет, Джон, работаете ли вы на stackoverflow? – Shiva

+2

@ Шива: Нет, я работаю в Google. –

24

Вы можете использовать SequenceEqual метод:

bool areEqual = firstArray.SequenceEqual(secondArray); 

Как уже упоминалось в комментариях, SequenceEqual требует .NET 3.5 (или LINQBridge, если вы используете VS2008 и ориентации более раннюю версию инфраструктуры).

+1

Самый эффективный способ, я думаю. –

+1

Не с точки зрения времени выполнения это не так. –

+1

@Veton: Это, безусловно, наименее печатающий! См. Ответ Джона за несколько дополнительных оптимизаций. – LukeH

3

Если вы хотите, чтобы это было очень быстро, вы можете использовать небезопасный код (что не всегда возможно):

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

Джон упоминается сравнивая несколько байт одновременно с использованием небезопасного кода, так что я должен был дать это идти:

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; 
} 

безопасный код получает довольно оптимизирован (компилятор знает, что он не должен проверять границы индекса, например), так что я не ожидал, что небезопасный код будет гораздо быстрее. Любое значительное различие может быть связано с возможностью одновременного сравнения нескольких байтов.

+0

Хорошая концепция, хотя код не компилируется:« Can not назначьте «p1», потому что это «фиксированная переменная» –

+0

@Edward Brey: Вы правы, это не сработает. Вам нужно объявить новые указатели внутри блока, чтобы они были изменены. Я исправил код. – Guffa

+0

Быстро использовать longs (8 байтов) в comp, даже на 32-битных машинах. – Joe

2

Если вы не слишком обеспокоены производительностью, вы можете рассмотреть IStructuralEquatable.

.NET Framework Поддерживается в версиях: 4.5, 4

Структурное равенство означает, что два объекта равны, потому что они имеют одинаковые значения. Он отличается от эталонного равенства.

Пример:

static bool ByteArrayCompare(byte[] a1, byte[] a2) 
{ 
    IStructuralEquatable eqa1 = a1; 
    return eqa1.Equals(a2, StructuralComparisons.StructuralEqualityComparer); 
} 

ССЫЛКА

  1. What problem does IStructuralEquatable and IStructuralComparable solve?
  2. Why aren't IStructuralEquatable and IStructuralComparable generic?
  3. IStructuralEquatable Interface
+1

Давая этот пост: это может быть способ сделать что-то, когда мы используем последние версии фреймворка. – timmi4sa

Смежные вопросы