2016-10-06 3 views
1

У моего объекта будет массив байтов, он может содержать тысячи элементов. Этот массив будет установлен во время построения, а затем никогда не будет изменен. Мне нужно иметь возможность сравнивать массивы с 2 отдельными объектами, чтобы увидеть, являются ли они одинаковыми.Неизменяемая коллекция Hashcode

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

Я планирую использовать что-то вроде этого Good GetHashCode() override for List of Foo objects respecting the order сразу после создания коллекции и хранения этого хэша для сравнения.

Мне интересно, существует ли неизменный тип коллекции, встроенный в C# или .Net, который уже делает это, или если есть лучший вариант, который я упустил.

+0

Что-то вроде этого? https://blogs.msdn.microsoft.com/dotnet/2013/09/25/immutable-collections-ready-for-prime-time/ – Darren

+2

HashCode - неплохая идея из-за возможного столкновения. В реальной жизни используется хэш-код, указывающий на то, что obejcts являются «возможными равными» или «определенно не равными». – pwas

+2

@nopeflow «определенно не равно» достаточно, чтобы избежать более дорогостоящих * SequenceEqual * проверяет каждый элемент ... SequenceEqual может использоваться только тогда, когда hashcodes равны .... –

ответ

1

Я собрал несколько разных методов сравнения массивов байтов, я использовал произвольную длину массива 10000 и предположил, что оба сравниваемых массива имеют одинаковую длину (поскольку проверка длины «широкой фазы», ​​очевидно, не является very interesting :))

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

Результатом является среднее из 5 итераций для трех сценариев (равное, первый элемент отличается и последний элемент разный), а тайминги - в мс.

--------------- 
Identical elements 
--------------- 
SequenceEqual: 5.98142 
BasicEqual: 0.11864 
UnsafeMemCmp: 0.15542 
SafeMemCmp: 0.12896 
--------------- 
First element different 
--------------- 
SequenceEqual: 0.00056 
BasicEqual: 0.00012 
UnsafeMemCmp: 0.0002 
SafeMemCmp: 0.00182 
--------------- 
Last element different 
--------------- 
SequenceEqual: 0.14942 
BasicEqual: 0.03178 
UnsafeMemCmp: 0.0015 
SafeMemCmp: 0.00326 
--------------- 

В 4 метода я выбрал являются:

SequentalEqual

static bool SequenceEqual(byte[] arr1, byte[] arr2) 
{ 
    return arr1.SequenceEqual(arr2); 
} 

BasicEqual

static bool BasicEqual(byte[] arr1, byte[] arr2) 
{ 
    for (var i = 0; i < 10000; i++) 
     if (arr1[i] != arr2[i]) 
      return false; 
    return true; 
} 

UnsafeMemCmp

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern unsafe int memcmp(byte* b1, byte* b2, int count); 

static unsafe bool UnsafeMemCmp(byte[] arr1, byte[] arr2) 
{ 
    fixed (byte* b1 = arr1, b2 = arr2) 
    { 
     return memcmp(b1, b2, 10000) == 0; 
    } 
} 

SafeMemCmp

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern int memcmp(IntPtr b1, IntPtr b2, int count); 

static bool SafeMemCmp(byte[] arr1, byte[] arr2) 
{ 
    var a = Marshal.AllocHGlobal(arr1.Length); 
    var b = Marshal.AllocHGlobal(arr2.Length); 

    try 
    {   
     Marshal.Copy(arr1, 0, a, arr1.Length); 
     Marshal.Copy(arr2, 0, b, arr2.Length); 

     return memcmp(a, b, 10000) == 0; 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(a); 
     Marshal.FreeHGlobal(b); 
    } 
} 

Для завершения испытания были проведены с использованием следующего метода:

static void RunTest(string name, Func<byte[], byte[], bool> action, byte[] a, byte[] b) 
{ 
    TimeSpan total = TimeSpan.Zero; 

    for (var i = 0; i < 5; i++) 
    { 
     _stopwatch.Reset(); 
     _stopwatch.Start(); 
     action(a, b); 
     _stopwatch.Stop(); 
     total += _stopwatch.Elapsed; 
    } 

    Console.WriteLine(name + ": " + (total.TotalMilliseconds/5)); 
} 
+0

спасибо ... У вас есть 'SafeEquals' в вашем списке - я предполагаю, что это карты для метода для BasicEqual в разделе кода. –

+1

Да, действительно, я изменил его после написания ответа ... Я отредактирую :) –

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