स्विफ्ट में रिवर्स ऑर्डर में लूप के लिए पुनरावृति कैसे करें?


186

जब मैं प्लेग्राउंड में लूप के लिए उपयोग करता हूं, तो सब कुछ ठीक काम करता है, जब तक कि मैंने लूप के पहले पैरामीटर को उच्चतम मूल्य नहीं दिया। (अवरोही क्रम में iterated)

क्या यह एक बग है? क्या किसी और के पास था?

for index in 510..509
{
    var a = 10
}

काउंटर जो पुनरावृत्तियों की संख्या प्रदर्शित करता है, जो टिक जाएगा ...

यहां छवि विवरण दर्ज करें



1
सी स्टाइल लूप्स को छोड़ने का ऐसा शानदार फैसला। उन्हें वापस लाएँ
जोएल टेपली

स्विफ्ट 5 के साथ मेरा जवाब देखें जो रिवर्स ऑर्डर में पुनरावृति करने के लिए 4 अलग-अलग तरीकों को दिखाता है।
इमानौ पेटिट

जवाबों:


229

Xcode 6 बीटा 4 में एक से दूसरे चरण के साथ पर्वतमाला पर पुनरावृति करने के लिए दो फ़ंक्शन जोड़े गए: stride(from: to: by:)जिसका उपयोग अनन्य श्रेणियों के साथ किया जाता है और stride(from: through: by:), जिसका उपयोग समावेशी श्रेणियों के साथ किया जाता है।

रिवर्स ऑर्डर में एक सीमा पर पुनरावृत्ति करने के लिए, उन्हें नीचे के रूप में इस्तेमाल किया जा सकता है:

for index in stride(from: 5, to: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2

for index in stride(from: 5, through: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2, 1

ध्यान दें कि दोनों में से कोई भी एक Rangeसदस्य फ़ंक्शन नहीं है। वे वैश्विक कार्य हैं जो या तो StrideToएक StrideThroughसंरचना है, जो Rangeसंरचना से भिन्न रूप से परिभाषित हैं ।

इस उत्तर के पिछले संस्करण में संरचना के by()सदस्य फ़ंक्शन का उपयोग किया गया Rangeथा, जिसे बीटा 4 में हटा दिया गया था। यदि आप यह देखना चाहते हैं कि यह कैसे काम करता है, तो संपादन इतिहास की जांच करें।


26
स्विफ्ट 2.0 के साथ यह अब है: 5.stride(to: 1, by: -1)या5.stride(through: 1, by: -1)
बिएरियन

6
स्विफ्ट 3.0 के साथ हम एक फ्री फंक्शन के रूप में आगे बढ़ने के लिए तैयार हैं।
Cezar

@ शॉन यह एक उचित और सुरक्षित विकल्प है। मैं आपको अक्सर यह नहीं बता सकता कि आर प्रोग्रामर इसके :संचालक द्वारा नीचे की ओर तिरछे तरीके से लगाए गए हैं, जिससे उनके लूप निष्पादित हो जाते हैं जब उन्हें लगा कि यह उन पर छोड़ देगा। यह इंटरैक्टिव उपयोग के लिए बहुत सुविधाजनक है, लेकिन लिपियों में बहुत त्रुटि हुई, उस बिंदु तक जहां शैली गाइड इसका उपयोग करने के खिलाफ सलाह देते हैं
काबर्रिक

212

रिवर्स फ़ंक्शन को श्रेणी में पीछे की ओर पुनरावृत्त करने के लिए लागू करें:

के लिए स्विफ्ट 1.2 और पूर्ववर्ती संस्करण:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}

यह आधी खुली श्रेणियों के साथ भी काम करता है:

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}

ध्यान दें: reverse(1...10)एक प्रकार की एक सरणी बनाता है [Int], इसलिए जब यह छोटी श्रेणियों के लिए ठीक हो सकता है, तो lazyनीचे दी गई जानकारी का उपयोग करना बुद्धिमानी होगी या strideयदि आपकी सीमा बड़ी है, तो स्वीकृत उत्तर पर विचार करें ।


एक बड़ी सरणी बनाने से बचने के लिए, lazyसाथ में उपयोग करें reverse()। निम्नलिखित परीक्षण एक खेल के मैदान में कुशलता से चलता है यह एक ट्रिलियन Intएस के साथ एक सरणी नहीं बना रहा है !

परीक्षा:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}

Xcode 7 में स्विफ्ट 2.0 के लिए :

for i in (1...10).reverse() {
    print(i)
}

ध्यान दें कि स्विफ्ट 2.0 में, (1...1_000_000_000_000).reverse()प्रकार का है ReverseRandomAccessCollection<(Range<Int>)>, इसलिए यह ठीक काम करता है:

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}

के लिए स्विफ्ट 3.0 reverse() को नाम दिया गया है reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}

3
reversedहालांकि संग्रह की प्रतिलिपि बना सकते हैं। कम से कम, यह है कि मैं प्रलेखन को कैसे समझता हूं Data
राफेल

96

स्विफ्ट 3 के लिए अपडेट किया गया

नीचे दिया गया उत्तर उपलब्ध विकल्पों का सारांश है। वह चुनें जो आपकी आवश्यकताओं के लिए सबसे उपयुक्त हो।

reversed: एक सीमा में संख्याएँ

आगे

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

पिछड़ा

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

reversed: में तत्व SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]

आगे

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat

पिछड़ा

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse

reversed: एक सूचकांक के साथ तत्व

कभी-कभी एक संग्रह के माध्यम से पुनरावृत्ति करते समय एक सूचकांक की आवश्यकता होती है। उसके लिए आप उपयोग कर सकते हैं enumerate(), जो टपल लौटाता है। टपल का पहला तत्व सूचकांक है और दूसरा तत्व वस्तु है।

let animals = ["horse", "cow", "camel", "sheep", "goat"]

आगे

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat

पिछड़ा

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse

ध्यान दें कि बेन लछमन ने अपने जवाब में कहा , आप शायद इसके .enumerated().reversed()बजाय करना चाहते हैं.reversed().enumerated() (जिससे सूचकांक संख्या में वृद्धि होगी)।

स्ट्राइड: संख्या

स्ट्राइड एक सीमा का उपयोग किए बिना पुनरावृति करने का तरीका है। इसके दो रूप हैं। कोड के अंत में टिप्पणियां दिखाती हैं कि रेंज संस्करण क्या होगा (वेतन वृद्धि का आकार 1 है)।

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex

आगे

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

पिछड़ा

वेतन वृद्धि का आकार बदलने से -1आप पिछड़ जाते हैं।

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

नोट toऔर throughअंतर।

स्ट्राइड: सीक्वेंसटाइप के तत्व

2 की वेतन वृद्धि से आगे

let animals = ["horse", "cow", "camel", "sheep", "goat"]

मैं 2इस उदाहरण में सिर्फ एक और संभावना दिखाने के लिए उपयोग कर रहा हूं ।

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat

पिछड़ा

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 

टिप्पणियाँ


52

स्विफ्ट 4 बाद में

for i in stride(from: 5, to: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1

for i in stride(from: 5, through: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1, 0

28

अपनी आवश्यकताओं के अनुसार, स्विफ्ट 5 के साथ, आप अपनी समस्या को हल करने के लिए प्लेग्राउंड कोड के चार उदाहरणों में से एक चुन सकते हैं ।


# 1। ClosedRange reversed()विधि का उपयोग करना

ClosedRangeनामक एक विधि है reversed()reversed()विधि में निम्नलिखित घोषणा है:

func reversed() -> ReversedCollection<ClosedRange<Bound>>

संग्रह के तत्वों को रिवर्स ऑर्डर में प्रस्तुत करने वाला एक दृश्य देता है।

उपयोग:

let reversedCollection = (0 ... 5).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

एक विकल्प के रूप में, आप Range reversed()विधि का उपयोग कर सकते हैं :

let reversedCollection = (0 ..< 6).reversed()

for index in reversedCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 2। sequence(first:next:)फ़ंक्शन का उपयोग करना

स्विफ्ट स्टैंडर्ड लाइब्रेरी नामक एक फ़ंक्शन प्रदान करता है sequence(first:next:)sequence(first:next:)निम्नलिखित घोषणा है:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldFirstSequence<T>

के एक क्रम से firstऔर बार-बार आलसी अनुप्रयोगों का गठन किया जाता है next

उपयोग:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 3। stride(from:through:by:)फ़ंक्शन का उपयोग करना

स्विफ्ट स्टैंडर्ड लाइब्रेरी नामक एक फ़ंक्शन प्रदान करता है stride(from:through:by:)stride(from:through:by:)निम्नलिखित घोषणा है:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

एक प्रारंभिक मूल्य से एक अनुक्रम लौटाता है, और संभवतया, एक अंतिम मान, निर्दिष्ट राशि से कदम बढ़ाना।

उपयोग:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

एक विकल्प के रूप में, आप इसका उपयोग कर सकते हैं stride(from:to:by:):

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

# 4। AnyIterator init(_:)इनिशियलाइज़र का उपयोग करना

AnyIteratorका इनिशियलाइज़र कहा जाता है init(_:)init(_:)निम्नलिखित घोषणा है:

init(_ body: @escaping () -> AnyIterator<Element>.Element?)

एक पुनरावृत्ति बनाता है जो दिए गए क्लोजर को अपनी next()विधि में लपेटता है ।

उपयोग:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator({ () -> Int? in
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

यदि आवश्यक हो, तो आप इसके लिए Intअपने विस्तारक को लपेटकर और उसके लिए एक विस्तार विधि बनाकर पिछले कोड को फिर से तैयार कर सकते हैं :

extension Int {

    func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
        var index = self
        guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }

        let iterator = AnyIterator { () -> Int? in
            defer { index = index - 1 }
            return index >= endIndex ? index : nil
        }
        return iterator
    }

}

let iterator = 5.iterateDownTo(0)

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

अनुक्रम (पहला: 5, अगला: {($ 0> 0)? ($ 0 - 1): nil}) // से अधिक सरल है ($ 0 - 1> = 0)
SirEnder

27

स्विफ्ट 2.0 के लिए और ऊपर आपको रेंज कलेक्शन पर रिवर्स अप्लाई करना चाहिए

for i in (0 ..< 10).reverse() {
  // process
}

इसे स्विफ्ट 3.0 में .reversed () में बदल दिया गया है



5

स्विफ्ट 4.0

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

यदि आप toमूल्य शामिल करना चाहते हैं :

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}

3

यदि कोई रिवर्स में किसी सरणी ( Arrayया अधिक सामान्यतः किसी भी SequenceType) के माध्यम से पुनरावृति करना चाहता है । आपके पास कुछ अतिरिक्त विकल्प हैं।

पहले आप reverse()सामान्य के रूप में इसके माध्यम से सरणी और लूप कर सकते हैं । हालाँकि, मैं enumerate()समय का बहुत अधिक उपयोग करना पसंद करता हूं क्योंकि यह एक टपल को वस्तु से जोड़ता है और यह सूचकांक है।

यहां एक बात ध्यान देने वाली है कि इन्हें सही क्रम में कॉल करना महत्वपूर्ण है:

for (index, element) in array.enumerate().reverse()

अवरोही क्रम में पैदावार अनुक्रमित करता है (जो कि मैं आमतौर पर उम्मीद करता हूं)। जहाँ तक:

for (index, element) in array.reverse().enumerate()(जो NSArray का एक करीबी मैच है reverseEnumerator)

सरणी को पीछे की ओर चलता है लेकिन आरोही अनुक्रमित को आउटपुट करता है।


3

स्विफ्ट 2.2, Xcode 7.3 (10, जून, 2016) के लिए:

for (index,number) in (0...10).enumerate() {
    print("index \(index) , number \(number)")
}

for (index,number) in (0...10).reverse().enumerate() {
    print("index \(index) , number \(number)")
}

आउटपुट:

index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10


index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0

2

आप whileइसके बजाय C- स्टाइल लूप का उपयोग करने पर विचार कर सकते हैं । यह स्विफ्ट 3 में ठीक काम करता है:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}

2

आप आसानी से रिवर्स मूल्यों के लिए उलट () विधि का उपयोग कर सकते हैं।

var i:Int
for i in 1..10.reversed() {
    print(i)
}

उलट () विधि मूल्यों को उलट देती है।


आप पहले से मौजूद एक के समान उत्तर क्यों जोड़ेंगे? (जैसे, @ रोहित।)
क्यूबर्निक

1
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.