Вы можете использовать enumerate
для преобразования последовательности ( Array
, String
и т. Д.) В последовательность кортежей с целочисленным счетчиком и элементом, соединенными вместе. То есть:
let numbers = [7, 8, 9, 10]
let indexAndNum: [String] = numbers.enumerate().map { (index, element) in
return "\(index): \(element)"
}
print(indexAndNum)
Ссылка на enumerate
определение
Обратите внимание, что это не то же самое, что получение индекса коллекции - enumerate
возвращает вам целочисленный счетчик. Это то же самое, что индекс для массива, но для строки или словаря не очень полезен. Чтобы получить фактический индекс вместе с каждым элементом, вы можете использовать zip
:
let actualIndexAndNum: [String] = zip(numbers.indices, numbers).map { "\($0): \($1)" }
print(actualIndexAndNum)
При использовании пронумерованной последовательности с reduce
вы не сможете разделить индекс и элемент в кортеже, поскольку у вас уже есть накопительный / текущий кортеж в сигнатуре метода. Вместо этого вам нужно будет использовать .0
и .1
для второго параметра вашего reduce
закрытия:
let summedProducts = numbers.enumerate().reduce(0) { (accumulate, current) in
return accumulate + current.0 * current.1
}
print(summedProducts)
Swift 3.0 и выше
Синтаксис Swift 3.0 совсем другой.
Кроме того, вы можете использовать short-syntax / inline для отображения массива в словаре:
let numbers = [7, 8, 9, 10]
let array: [(Int, Int)] = numbers.enumerated().map { ($0, $1) }
Это дает:
[(0, 7), (1, 8), (2, 9), (3, 10)]
numbers.enumerate().map { (index, element) in ...
.reduce
послеenumerate()
илиzip
.enumerate
сейчасenumerated
Для
Swift 2.1
I написал следующую функцию:extension Array { public func mapWithIndex<T> (f: (Int, Element) -> T) -> [T] { return zip((self.startIndex ..< self.endIndex), self).map(f) } }
А затем используйте это так:
let numbers = [7, 8, 9, 10] let numbersWithIndex: [String] = numbers.mapWithIndex { (index, number) -> String in return "\(index): \(number)" } print("Numbers: \(numbersWithIndex)")
источник
В Swift 3, когда у вас есть объект, соответствующий
Sequence
протоколу, и вы хотите связать каждый элемент внутри него с его индексом, вы можете использоватьenumerated()
метод.Например:
let array = [1, 18, 32, 7] let enumerateSequence = array.enumerated() // type: EnumerateSequence<[Int]> let newArray = Array(enumerateSequence) print(newArray) // prints: [(0, 1), (1, 18), (2, 32), (3, 7)]
let reverseRandomAccessCollection = [1, 18, 32, 7].reversed() let enumerateSequence = reverseRandomAccessCollection.enumerated() // type: EnumerateSequence<ReverseRandomAccessCollection<[Int]>> let newArray = Array(enumerateSequence) print(newArray) // prints: [(0, 7), (1, 32), (2, 18), (3, 1)]
let reverseCollection = "8763".characters.reversed() let enumerateSequence = reverseCollection.enumerated() // type: EnumerateSequence<ReverseCollection<String.CharacterView>> let newArray = enumerateSequence.map { ($0.0 + 1, String($0.1) + "A") } print(newArray) // prints: [(1, "3A"), (2, "6A"), (3, "7A"), (4, "8A")]
Поэтому в простейшем случае вы можете реализовать алгоритм Луна на игровой площадке следующим образом:
let array = [8, 7, 6, 3] let reversedArray = array.reversed() let enumerateSequence = reversedArray.enumerated() let luhnClosure = { (sum: Int, tuple: (index: Int, value: Int)) -> Int in let indexIsOdd = tuple.index % 2 == 1 guard indexIsOdd else { return sum + tuple.value } let newValue = tuple.value == 9 ? 9 : tuple.value * 2 % 9 return sum + newValue } let sum = enumerateSequence.reduce(0, luhnClosure) let bool = sum % 10 == 0 print(bool) // prints: true
Если вы начнете с a
String
, вы можете реализовать это так:let characterView = "8763".characters let mappedArray = characterView.flatMap { Int(String($0)) } let reversedArray = mappedArray.reversed() let enumerateSequence = reversedArray.enumerated() let luhnClosure = { (sum: Int, tuple: (index: Int, value: Int)) -> Int in let indexIsOdd = tuple.index % 2 == 1 guard indexIsOdd else { return sum + tuple.value } let newValue = tuple.value == 9 ? 9 : tuple.value * 2 % 9 return sum + newValue } let sum = enumerateSequence.reduce(0, luhnClosure) let bool = sum % 10 == 0 print(bool) // prints: true
Если вам нужно повторить эти операции, вы можете преобразовать код в расширение:
extension String { func luhnCheck() -> Bool { let characterView = self.characters let mappedArray = characterView.flatMap { Int(String($0)) } let reversedArray = mappedArray.reversed() let enumerateSequence = reversedArray.enumerated() let luhnClosure = { (sum: Int, tuple: (index: Int, value: Int)) -> Int in let indexIsOdd = tuple.index % 2 == 1 guard indexIsOdd else { return sum + tuple.value } let newValue = tuple.value == 9 ? 9 : tuple.value * 2 % 9 return sum + newValue } let sum = enumerateSequence.reduce(0, luhnClosure) return sum % 10 == 0 } } let string = "8763" let luhnBool = string.luhnCheck() print(luhnBool) // prints: true
Или, очень кратко:
extension String { func luhnCheck() -> Bool { let sum = characters .flatMap { Int(String($0)) } .reversed() .enumerated() .reduce(0) { let indexIsOdd = $1.0 % 2 == 1 guard indexIsOdd else { return $0 + $1.1 } return $0 + ($1.1 == 9 ? 9 : $1.1 * 2 % 9) } return sum % 10 == 0 } } let string = "8763" let luhnBool = string.luhnCheck() print(luhnBool) // prints: true
источник
В дополнение к примеру Нейта Кука
map
, вы также можете применить это поведение кreduce
.let numbers = [1,2,3,4,5] let indexedNumbers = reduce(numbers, [:]) { (memo, enumerated) -> [Int: Int] in return memo[enumerated.index] = enumerated.element } // [0: 1, 1: 2, 2: 3, 3: 4, 4: 5]
Обратите внимание, что
EnumerateSequence
переданные в замыкание asenumerated
не могут быть разложены вложенным образом, поэтому элементы кортежа должны быть разложены внутри замыкания (т.е.enumerated.index
).источник
Это рабочее расширение CollectionType для swift 2.1 с использованием бросков и повторных бросков:
extension CollectionType { func map<T>(@noescape transform: (Self.Index, Self.Generator.Element) throws -> T) rethrows -> [T] { return try zip((self.startIndex ..< self.endIndex), self).map(transform) } }
Я знаю, что это не то, о чем вы спрашивали, но решает вашу проблему. Вы можете попробовать этот быстрый метод 2.0 Luhn, ничего не расширяя:
func luhn(string: String) -> Bool { var sum = 0 for (idx, value) in string.characters.reverse().map( { Int(String($0))! }).enumerate() { sum += ((idx % 2 == 1) ? (value == 9 ? 9 : (value * 2) % 9) : value) } return sum > 0 ? sum % 10 == 0 : false }
источник