Расширение Swift Array для замены значения индекса n суммой n-предыдущих значений - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь написать расширение для типов массивов, которое суммирует n-предыдущие индексы в индексе n.

let myArray = [1, 2, 3, 4, 5]
let mySumArray = myArray.sumNIndex()
print(mySumArray)
// returns [1,3,6,10,15]

Я пробовал различные подходы, которые в какой-то момент потерпели неудачу.Например, приведенный ниже пример вызывает ошибку компиляции " Невозможно вызвать" Reduce "со списком аргументов типа" (Int, _) ' ":

extension Array {
    mutating func indexSum() {
        var tempArray = [Any]()
        for index in 1...self.count - 1 {
        self[index] += self[.prefix(index + 2).reduce(0, +)]
        }
    }
}

Эта другая попытка запускаетдругая ошибка компиляции: « Двоичный оператор '+ =' нельзя применить к двум операндам« Элемента »"

extension Array {
    mutating func indexSum() {
        var tempArray = [Any]()
        for index in 1...self.count - 1 {
        self[index] += self[index - 1]
        }
    }
}

Любая идея приветствуется!Большое спасибо за вашу помощь!

РЕДАКТИРОВАТЬ: Большое спасибо @Martin и @Carpsen, которые выяснили это двумя различными способами

@ Мартин, используя метод карты:

extension Array where Element: Numeric {
    func cumulativeSum() -> [Element] {
        var currentSum: Element = 0
        return map {
            currentSum += $0
            return currentSum
        }
    }
}

@ Карпсен, используя метод уменьшения:

extension Array where Element: Numeric {
    func indexSum() -> [Element] {
        return self.reduce(into: [Element]()) {(acc, element) in
            return acc + [(acc.last ?? 0) + element]
        })
    }
}

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Попробуйте это:

let myArray = [1, 2, 3, 4, 5]

myArray.reduce([Int](), {accumulator, element in
    return accumulator + [(accumulator.last ?? 0) + element]
})
//[1, 3, 6, 10, 15]

Что делает reduce:

  • Начните с пустого массива
  • С каждым элементом из myArrayон вычисляет сумму с последним элементом в accumulator
  • Возвращает предыдущий массив плюс последний сумма

Вот более простая, но более длинная версия:

let myArray = [1, 2, 3, 4, 5]

let newArray = myArray.reduce([Int](), {accumulator, element in
    var tempo = accumulator
    let lastElementFromTheAccumulator = accumulator.last ?? 0
    let currentSum = element + lastElementFromTheAccumulator
    tempo.append(currentSum)
    return tempo
})

print(newArray)  //[1, 3, 6, 10, 15]

Более эффективное решение, предложенное Martin R в комментариях, использует reduce(into:):

myArray.reduce(into: [Int]()) { (accumulator, element) in
    accumulator += [(accumulator.last ?? 0) + element]
}
//[1, 3, 6, 10, 15]

И вы можете иметь его как расширение:

extension Array where Element: Numeric {
    func indexSum() -> [Element] {
        return self.reduce([Element](), {acc, element in
            return acc + [(acc.last ?? 0) + element]
        })
    }
}

myArray.indexSum()  //[1, 3, 6, 10, 15]

Вот решение, которое будет работать и со строками:

extension Array where Element == String {
    func indexSum() -> [String] {
        return self.reduce(into: [String]()) {(accumulator, element) in
            accumulator += [(accumulator.last ?? "") + element]
        }
    }
}

["a", "b", "c", "d"].indexSum() //["a", "ab", "abc", "abcd"]

Если вы хотите иметь разделитель между элементами начальных элементов массива, вы можете использовать это расширение:

extension Array where Element == String {
    func indexSum(withSparator: String) -> [String] {
        return self.reduce(into: [String]()) {(accumulator, element) in
            var previousString = ""
            if let last = accumulator.last {
                previousString = last + " "
            }
            accumulator += [previousString +  element]
        }
    }
}

["a", "b", "c", "d"].indexSum(withSparator: " ") //["a", "a b", "a b c", "a b c d"]
0 голосов
/ 02 октября 2018

Основная проблема заключается в том, что оператор сложения + не определен для элементов произвольных массивов.Вам нужно ограничить метод расширения, например, массивами Numeric элементов.

Также нет необходимости использовать Any.

. Вот возможная реализация в качестве неизменяемойmethod:

extension Array where Element: Numeric {
    func cumulativeSum() -> [Element] {
        var currentSum: Element = 0
        return map {
            currentSum += $0
            return currentSum
        }
    }
}

Примеры:

let intArray = [1, 2, 3, 4, 5]
print(intArray.cumulativeSum()) // [1, 3, 6, 10, 15]

let floatArray = [1.0, 2.5, 3.25]
print(floatArray.cumulativeSum()) [1.0, 3.5, 6.75]

Аналогичным образом мы можем «кумулятивно объединять» элементы массива строк.enumerated() теперь используется для предоставления текущего индекса элемента вместе с элементом, и это используется для определения, вставлять разделитель или нет:

extension Array where Element == String {
    func cumulativeJoin(separator: String) -> [Element] {
        var currentJoin = ""
        return enumerated().map { (offset, elem) in
            if offset > 0 { currentJoin.append(separator) }
            currentJoin.append(elem)
            return currentJoin
        }
    }
}

Примеры:

let stringArray = ["a", "b", "c"]
print(stringArray.cumulativeJoin()) // ["a", "ab", "abc"]
print(stringArray.cumulativeJoin(separator: ":")) // ["a", "a:b", "a:b:c"]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...