Сравнение быстрых массивов в Swift 4.2

У меня есть два целочисленных массива, содержащих 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
}

person Community    schedule 02.03.2019    source источник
comment
Будет ли их сортировать быстрее?   -  person MadProgrammer    schedule 02.03.2019
comment
@MadProgrammer, мне нужны index и element. Так что сортировать не надо...   -  person    schedule 02.03.2019
comment
Этот процесс занял 4 секунды больше времени. ???   -  person Alexander    schedule 02.03.2019
comment
Вы отбрасываете результат всей этой операции. Так что именно вы пытаетесь сделать?   -  person Alexander    schedule 02.03.2019
comment
@Александр, мне важен результат всей операции. Я пытаюсь сократить время отображения. Я не знаю, что мне нужно использовать. Итак, я использовал compactMaping для сравнения. Но для завершения цикла требуется 4 секунды.   -  person    schedule 02.03.2019
comment
@Aishu Возможно, вы могли бы ускорить его, используя простой map вместо compactMap. Вы не возвращаете необязательный (вроде), поэтому вам не нужно использовать compactMap. На самом деле, ваше выражение d2[index] == value ? 0 : value неявно повышается до необязательного только для того, чтобы compactMap потом пришлось тратить время на его распаковку.   -  person Alexander    schedule 02.03.2019
comment
@Александр, хорошо. Я обновил вопрос с вашим предложением. Это точно ты сказал? Теперь для завершения цикла требуется 2 секунды, иногда 3 секунды.   -  person    schedule 02.03.2019


Ответы (1)


Вероятно, вы могли бы ускорить его, используя простую карту вместо compactMap. Вы не возвращаете необязательный (вроде), поэтому вам не нужно использовать compactMap. Фактически, ваше выражение d2[index] == value ? 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 из-за его удобочитаемости. Если производительность абсолютно критична, до такой степени, что вы решили, что можно пожертвовать читабельностью и удобством сопровождения ради крошечных прибавок к скорости, тогда, возможно, стоит переключиться на ручное индексирование, но это очень маловероятно. быть дело.

person Alexander    schedule 02.03.2019