신속하게 for 루프를 역순으로 반복하는 방법은 무엇입니까?


187

놀이터에서 for 루프를 사용하면 for 루프의 첫 번째 매개 변수가 가장 높은 값으로 변경 될 때까지 모든 것이 잘 작동했습니다. (내림차순으로 인용)

이것이 버그입니까? 다른 사람이 있습니까?

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

실행될 반복 횟수를 표시하는 카운터는 계속 똑딱 거립니다.

여기에 이미지 설명을 입력하십시오



1
c 스타일 루프를 삭제하려는 훌륭한 결정입니다. 그들을 다시 가져 오십시오
Joel Teply

최대 4 가지 방법으로 역순으로 반복되는 Swift 5의 대답을 참조하십시오 .
Imanou Petit

답변:


230

: 엑스 코드 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.

이 답변의 이전 버전은 베타 4에서 제거 된 구조체 의 by()멤버 함수를 사용했습니다.이 기능이 Range어떻게 작동하는지 보려면 편집 기록을 확인하십시오.


26
Swift 2.0을 사용하면 현재는 다음 5.stride(to: 1, by: -1)과 같습니다.5.stride(through: 1, by: -1)
Binarian

6
Swift 3.0을 통해 우리는 다시 무료 기능으로 발전했습니다.
Cezar

@ 숀 그것은 합리적이고 안전한 선택입니다. R 프로그래머가 :암시 적으로 아래쪽으로 반복하여 루프를 건너 뛸 것이라고 생각했을 때 루프가 실행되는 경우 가 종종 있습니다. 대화식 사용에는 매우 편리하지만 스크립트에서 오류가 발생하기 쉬우므로 스타일 가이드가 사용하지 않는 것이 좋습니다 .
Davor Cubranic

213

뒤로 반복하는 범위에 역 기능을 적용하십시오.

대한 스위프트 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(). 다음 테스트는 놀이터에서 효율적으로 실행되어 1 조 개의 배열을 만들지 않음을 보여줍니다 Int!

테스트:

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

대한 스위프트 2.0 엑스 코드 7 :

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

Swift 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.
Raphael

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

Ben Lachman이 그의 답변 에서 언급했듯이 (색인 수를 늘리기 .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

tothrough차이점에 유의하십시오 .

보폭 : SequenceType의 요소

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

Swift 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
*/

#삼. stride(from:through:by:)기능 사용

Swift Standard Library는라는 기능을 제공합니다 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
*/

sequence (first : 5, next : {($ 0> 0)? ($
0-1

27

Swift 2.0 이상에서는 범위 콜렉션에 역을 적용해야합니다

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

Swift 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또는 일반적으로 any 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 (2016 년 6 월 10 일) :

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

값을 쉽게 역전시키기 위해 reversed () 메소드를 사용할 수 있습니다.

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

reversed () 메소드는 값을 반대로합니다.


기존 답변과 동일한 답변을 추가하는 이유는 무엇입니까? (예 : @ Rohit 's)
Davor Cubranic

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

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.