在Swift中用索引映射或者减less

有没有办法在map获取数组的索引或reduce在Swift中? 我正在寻找类似于Ruby中的each_with_index

 func lunhCheck(number : String) -> Bool { var odd = true; return reverse(number).map { String($0).toInt()! }.reduce(0) { odd = !odd return $0 + (odd ? ($1 == 9 ? 9 : ($1 * 2) % 9) : $1) } % 10 == 0 } lunhCheck("49927398716") lunhCheck("49927398717") 

我想摆脱上面的oddvariables。

您可以使用enumerate将序列( ArrayString等)转换为具有整数计数器和元素配对在一起的元组序列。 那是:

 let numbers = [7, 8, 9, 10] let indexAndNum: [String] = numbers.enumerate().map { (index, element) in return "\(index): \(element)" } print(indexAndNum) // ["0: 7", "1: 8", "2: 9", "3: 10"] 

链接enumerate定义

请注意,这与获取collection的索引不同 – enumerate返回一个整数计数器。 这与数组的索引相同,但string或字典不会很有用。 要获得每个元素的实际索引,可以使用zip

 let actualIndexAndNum: [String] = zip(numbers.indices, numbers).map { "\($0): \($1)" } print(actualIndexAndNum) // ["0: 7", "1: 8", "2: 9", "3: 10"] 

当使用带有reduce的枚举序列时,由于方法签名中已经有了累加/当前元组,所以不能将索引和元素分开。 相反,您需要在第二个参数上使用.0.1reduce闭包:

 let summedProducts = numbers.enumerate().reduce(0) { (accumulate, current) in return accumulate + current.0 * current.1 // ^ ^ // index element } print(summedProducts) // 56 

Swift 3.0

由于Swift 3.0的语法是完全不同的。
此外,您可以使用短语法/内联来映射字典上的数组:

 let numbers = [7, 8, 9, 10] let array: [(Int, Int)] = numbers.enumerated().map { ($0, $1) } // ^ ^ // index element 

这产生:

 [(0, 7), (1, 8), (2, 9), (3, 10)] 

对于Swift 2.1我写了下面的函数:

 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")] 

因此,在最简单的情况下,你可以像这样在Playground中实现一个Luhnalgorithm:

 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 

如果你从一个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 

除了Nate Cook的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传递给闭包的EnumerateSequence不能以嵌套方式分解,因此元组的成员必须在闭包(即enumerated.index )内分解。

这是一个适用于swift 2.1的使用throws和rethrows的工作CollectionType扩展:

 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) } } 

我知道这不是你问的,而是解决你的问题。 你可以试试这个swift 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 }