Сравнение двухбайтовых массивов в .NET - PullRequest
487 голосов
/ 04 сентября 2008

Как я могу сделать это быстро?

Конечно, я могу сделать это:

static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i=0; i<a1.Length; i++)
        if (a1[i]!=a2[i])
            return false;

    return true;
}

Но я ищу либо функцию BCL , либо какой-нибудь высоко оптимизированный проверенный способ сделать это.

java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);

работает хорошо, но не похоже, что это будет работать для x64.

Обратите внимание на мой сверхбыстрый ответ здесь .

Ответы [ 27 ]

1 голос
/ 01 сентября 2017

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

static bool ByteArrayEquals(byte[] a1, byte[] a2) 
{
    return a1.Zip(a2, (l, r) => l == r).All(x => x);
}
0 голосов
/ 02 июля 2014

Если вы ищете очень быстрый компаратор равенства байтовых массивов, я предлагаю вам взглянуть на эту статью STSdb ​​Labs: Сравнитель равенств байтовых массивов. В нем представлены некоторые из самых быстрых реализаций для байта [] Сравнение на равенство массивов, которые представлены, протестированы и обобщены на производительность.

Вы также можете сосредоточиться на следующих реализациях:

BigEndianByteArrayComparer - быстрый сравнитель массива byte [] слева направо (BigEndian) BigEndianByteArrayEqualityComparer - - быстрое сравнение байтов [] слева направо (BigEndian) LittleEndianByteArrayComparer - быстрый алгоритм сравнения байтов [] справа налево (LittleEndian) LittleEndianByteArrayEqualityComparer - быстрое сравнение байтов [] справа налево (LittleEndian)

0 голосов
/ 07 февраля 2018

Поскольку многие из вышеперечисленных решений не работают с UWP, и поскольку я люблю Linq и функциональные подходы, я представляю вам свою версию этой проблемы. Чтобы избежать сравнения при возникновении первого различия, я выбрал .FirstOrDefault ()

public static bool CompareByteArrays(byte[] ba0, byte[] ba1) =>
    !(ba0.Length != ba1.Length || Enumerable.Range(1,ba0.Length)
        .FirstOrDefault(n => ba0[n] != ba1[n]) > 0);
0 голосов
/ 11 ноября 2013

Если у вас есть огромный массив байтов, вы можете сравнить их, преобразовав их в строку.

Вы можете использовать что-то вроде

byte[] b1 = // Your array
byte[] b2 = // Your array
string s1 = Encoding.Default.GetString( b1 );
string s2 = Encoding.Default.GetString( b2 );

Я использовал это, и я увидел огромное влияние на производительность.

0 голосов
/ 04 сентября 2008

Извините, если вы ищете управляемый способ, вы уже делаете это правильно, и, насколько мне известно, в BCL нет встроенного метода для этого.

Вы должны добавить несколько начальных нулевых проверок, а затем просто повторно использовать их, как если бы они находились в BCL.

0 голосов
/ 23 апреля 2015

Используйте SequenceEquals для сравнения.

0 голосов
/ 09 июня 2015

Краткий ответ таков:

    public bool Compare(byte[] b1, byte[] b2)
    {
        return Encoding.ASCII.GetString(b1) == Encoding.ASCII.GetString(b2);
    }

Таким образом, вы можете использовать оптимизированное сравнение строк .NET для сравнения байтового массива без необходимости писать небезопасный код. Вот как это делается на фоне :

private unsafe static bool EqualsHelper(String strA, String strB)
{
    Contract.Requires(strA != null);
    Contract.Requires(strB != null);
    Contract.Requires(strA.Length == strB.Length);

    int length = strA.Length;

    fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
    {
        char* a = ap;
        char* b = bp;

        // Unroll the loop

        #if AMD64
            // For the AMD64 bit platform we unroll by 12 and
            // check three qwords at a time. This is less code
            // than the 32 bit case and is shorter
            // pathlength.

            while (length >= 12)
            {
                if (*(long*)a     != *(long*)b)     return false;
                if (*(long*)(a+4) != *(long*)(b+4)) return false;
                if (*(long*)(a+8) != *(long*)(b+8)) return false;
                a += 12; b += 12; length -= 12;
            }
       #else
           while (length >= 10)
           {
               if (*(int*)a != *(int*)b) return false;
               if (*(int*)(a+2) != *(int*)(b+2)) return false;
               if (*(int*)(a+4) != *(int*)(b+4)) return false;
               if (*(int*)(a+6) != *(int*)(b+6)) return false;
               if (*(int*)(a+8) != *(int*)(b+8)) return false;
               a += 10; b += 10; length -= 10;
           }
       #endif

        // This depends on the fact that the String objects are
        // always zero terminated and that the terminating zero is not included
        // in the length. For odd string sizes, the last compare will include
        // the zero terminator.
        while (length > 0)
        {
            if (*(int*)a != *(int*)b) break;
            a += 2; b += 2; length -= 2;
        }

        return (length <= 0);
    }
}
...