स्विफ्ट में इंडेक्स के साथ मैप या कम करें


143

क्या सरणी का सूचकांक प्राप्त करने का एक तरीका है mapया reduceस्विफ्ट में? मैं 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 और इसके बाद के संस्करण

चूंकि स्विफ्ट 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 check को एक gist में डाल दिया: gist.github.com/natecook1000/1eb756d6b10297006757
Nate Cook

5
स्विफ्ट 2.0 में आपको करने की आवश्यकता है:numbers.enumerate().map { (index, element) in ...
रॉबर्ट

@CharlieMartin: आप के .reduceबाद enumerate()या का उपयोग कर सकते हैं zip
नैट कुक

लेकिन एक सूचकांक के साथ? मुझे एक त्रुटि मिलती है कि फ़ंक्शन को केवल दो मापदंडों की आवश्यकता होती है और कम करने के लिए इनटल ऑब्जेक्ट (कम होने का परिणाम) लेता है, पहला परम के रूप में और दूसरा मान वर्तमान के रूप में पुनरावृत्त होता है। मैं वर्तमान में केवल for..in का उपयोग कर रहा हूं
चार्ली मार्टिन

स्विफ्ट 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

स्विफ्ट 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

नैट कुक के उदाहरण के अलावा 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

यह थ्रोट और रीथ्रो का उपयोग करके स्विफ्ट 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 लुहान विधि को आजमा सकते हैं:

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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.