Какой самый быстрый способ проверить 2 массива фиксированного размера на равенство в Swift? - PullRequest
0 голосов
/ 28 февраля 2020

А почему?

Учитывая следующий код Swift:

struct DemoStruct {
    let buf: [UInt8]

    init?(fromArray buf: [UInt8]) {
        guard buf.count == 6 else {
            return nil
        }
        self.buf = buf
    }

    var containsJustZeros: Bool {
        // test code
    }
}

let data = DemoStruct(fromArray: Array(repeating: 0, count: 6))!
if data.containsJustZeros {
    print("zeros")
}

Для части test code я реализовал и измерил следующие реализации:

  1. self.buf == Array(repeating: 0, count: 6)
  2. for dig in self.buf where dig != 0 { return false } return true
  3. self.buf.elementsEqual(Array(repeating: 0, count: 6))

В то время как первый код является самым быстрым (~ 13 с / 10 000 000 тестов) и последний самый медленный (~ 43 сек / 10 000 000 тестов). Возможна ли другая реализация? Я хотел бы оптимизировать мой код для скорости и лучше понять Swift.

1 Ответ

1 голос
/ 28 февраля 2020

Прежде всего: эта Data структура является действительно плохой идеей, которая почти наверняка приведет к путанице. У Foundation уже есть структура с именем Data, и она полностью вездесуща, потому что это тип «единой валюты» для перемещения по нетипизированным байтам разных данных.

Более того, вы ничего не получите от используя [UInt8]. Просто используйте Foundation.Data.

Что касается вашего основного вопроса.

  1. Первый метод выделяет массив и использует == для его сравнения. Нет абсолютно никаких причин выделять 6 нулей. Если бы у buf были элементы биллиона, вы бы выделили миллиард элементов? Расточительный.
  2. Второй метод лучше, потому что вы не выделяете ненужный элемент, просто для сравнения. Однако это ручная функция, которая уже существует в стандартной библиотеке (allSatisfy(_:), о которой я расскажу позже.)
  3. elementsEqual - более обобщенная c версия == , который может сравнить одну последовательность с любой другой последовательностью. Вы решили сравнить его с массивом из 6 нулей, но это плохо (по той же причине, что и 0). Вместо этого вы можете использовать repeatElement(0, count: 6) для создания элемента, который на самом деле не должен хранить n копий. Он хранит только один и упаковывает его так, чтобы он соответствовал протоколу Collection.

Лучший из всех подходов - просто использовать allSatisfy. Это быстро, не выделяет ничего лишнего, и , что наиболее важно , описывает, что именно вы пытаетесь express:

var containsJustZeros: Bool {
    self.buf.allSatisfy { byte in byte == 0 }
}

Однако я бы не стал реализовывать это в компьютерной собственности. Те, у кого есть традиционное ожидание быстрой скорости, тогда как при этом выполняется линейное сканирование всего буфера. Если вы не хотите кэшировать результат в сохраненном логическом свойстве, я бы изменил его на func.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...