Быстрое сравнение массивов в Swift 4.2 - PullRequest
0 голосов
/ 02 марта 2019

У меня есть два целочисленных массива, которые содержат 11059200 элементов.Из приведенного ниже примера

я делаю для изменения значения массива d1 на 0, сравнивая индекс элемента в d2

Время вычисления программы ниже

Comparing started: 2019-03-02 08:45:56 +0000
Comparing finished: 2019-03-02 08:46:00 +0000

Этот процесс занял 4 секунды, больше времени.

Я хочу сократить время.Есть ли какие-либо возможности?Спасибо

var d1 = [Int]()
var d2 = [Int]()

let value = 11059200

for _ in 0...value{

    d1.append(Int.random(in: 0...value))
    d2.append(Int.random(in: 0...value))
}

print("Comparing started: \(Date())")

var _ = d1.enumerated().compactMap { (index,value) -> Int in

    return d2[index] == value ? 0 : value
}

print("Comparing finished: \(Date())")

Обновление:

Согласно комментарию Александра, я использую карту, чтобы сократить время с 2-3 секунд

var _ = d1.enumerated().map { (index,value) -> Int in
  return d2[index] == value ? 0 : value
}

1 Ответ

0 голосов
/ 02 марта 2019

Возможно, вы могли бы ускорить его, используя простую карту вместо CompactMap.Вы не возвращаете Optional (вроде), поэтому вам не нужно использовать compactMap.На самом деле ваше выражение d2 [index] == значение?0: значение неявно повышается до необязательного, только для compactMap, чтобы затем тратить время на его развертывание.

Кроме того, вы можете упростить код, используя zip для итерации двух последовательностей:

import Foundation

func printTimeElapsedWhenRunningCode(title: String, operation: () -> Void) {
    let startTime = CFAbsoluteTimeGetCurrent()
    operation()
    let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
    print("Time elapsed for \(title): \(timeElapsed) s.")
}

let max = 11059200

let d1 = (0...max).map { _ in Int.random(in: 0...max) }
let d2 = (0...max).map { _ in Int.random(in: 0...max) }

printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using compactMap (original)") {
    let result = d1.enumerated().compactMap { index, value -> Int in
        return d2[index] == value ? 0 : value
    }

    print(result.count)
}

printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using map") {
    let result = d1.enumerated().map { index, value -> Int in
        return d2[index] == value ? 0 : value
    }

    print(result.count)
}

// just for a benchmark, don't write codel like this.
printTimeElapsedWhenRunningCode(title: "Manual Indexing") {
    var result = Array<Int>()
    result.reserveCapacity(d1.count)
    for i in d1.indices {
        let (d1Value, d2Value) = (d1[i], d2[i])
        let newValue = d1Value == d2Value ? 0 : d1Value
        result.append(newValue)
    }

    print(result.count)
}

// "Best" from a readibility stand-point
printTimeElapsedWhenRunningCode(title: "Zip") {
    let result = zip(d1, d2).map { d1Value, d2Value in
        return d1Value == d2Value ? 0 : d1Value
    }

    print(result.count)
}

Вот предварительные результаты в неоптимизированной сборке.Это абсолютно бессмысленно .Цель отладочных сборок состоит в том, чтобы компилятор создал правильную работоспособную программу в кратчайшие сроки с абсолютно нулевым вниманием к производительности.Он отлично подходит для быстрой итерации разработки, но бесполезен для бенчмаркинга.

Время, затраченное на перечисление и индексирование, сравнение с использованием compactMap (оригинал): 6.206556916236877 с.

Время, потраченное на ручное управлениеИндексирование: 0,3380240201950073 с.

Время, прошедшее для Zip: 7.123739957809448 с.

Время, прошедшее для перечисления и индексации, сравнение с использованием карты: 5.2529460191726685 с.

Когда вывключив оптимизацию (флаг -O в swiftc cli или в качестве опции в вашей цели сборки Xcode), вы получите совершенно другую картину:

Время, прошедшее для перечисления и индексации,сравнение с использованием compactMap (оригинал): 0,5904990434646606 с.

Время, затраченное на перечисление и индексирование, сравнение с использованием карты: 0,22207605838775635 с.

Время, потраченное на ручное индексирование: 0,18644499778747559 с.

* Прошедшее время для Zip: 0,2339940071105957 с.

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

...