Swift에서 색인으로 매핑 또는 축소


143

Swift 에서 map또는 reduceSwift에서 배열의 인덱스를 얻는 방법이 있습니까? 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")

odd변수를 제거하고 싶습니다 .

답변:


314

정수 카운터 및 요소가 쌍을 이루는 enumerate시퀀스 ( Array, String등)를 튜플 시퀀스로 변환하는 데 사용할 수 있습니다 . 그건:

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정의에 연결

이것은 컬렉션 의 인덱스 를 얻는 것과 같지 않습니다 enumerate. 정수 카운터를 돌려줍니다. 이것은 배열의 인덱스와 동일하지만 문자열이나 사전에 유용하지 않습니다. 각 요소와 함께 실제 색인을 얻으려면 다음을 사용할 수 있습니다 zip.

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

을 사용하여 열거 형 시퀀스를 사용하는 reduce경우 메소드 서명에 이미 누적 / 현재 튜플이 있으므로 튜플에서 인덱스와 요소를 분리 할 수 ​​없습니다. 대신 사용해야합니다 .0그리고 .1당신의 두 번째 매개 변수에 reduce폐쇄 :

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

스위프트 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)]

1
마무리의 재미를 훔치고 싶지 않기 때문에 필요한 경우 수정 된 Luhn 검사를 대답 대신에 요점에 넣습니다. gist.github.com/natecook1000/1eb756d6b10297006137
Nate Cook

5
swift 2.0에서해야 할 일 :numbers.enumerate().map { (index, element) in ...
Robert

@CharlieMartin : 또는 .reduce후에 사용할 수 있습니다 . enumerate()zip
Nate Cook

그러나 색인이 있습니까? 함수에 두 개의 매개 변수 만 필요하고 reduce는 첫 번째 매개 변수로 inital 객체 (감소 결과)를 가져오고 두 번째로 반복되는 현재 값을 가져 오는 오류가 발생합니다. 저는 현재 대신 for..in을 사용하고 있습니다
Charlie Martin

스위프트 5 enumerate에서 지금enumerated
lustig

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

8

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

따라서 가장 간단한 경우 다음과 같이 놀이터에서 Luhn 알고리즘을 구현할 수 있습니다.

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

2

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로 폐쇄에 전달 enumerated중첩 방식으로 분해 될 수는, 따라서 튜플의 멤버는 폐쇄 내부 분해되어야한다 (예. enumerated.index).


2

이것은 throw 및 rethrows를 사용하여 신속한 2.1을위한 작동하는 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)
    }

}

나는 이것이 당신이 요구 한 것이 아니라 문제를 해결한다는 것을 알고 있습니다. 당신은 아무것도 확장하지 않고이 신속한 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
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.