Swift의 역 범위


105

Swift에서 역 범위로 작업하는 방법이 있습니까?

예를 들면 :

for i in 5...1 {
  // do something
}

무한 루프입니다.

최신 버전의 Swift에서는 해당 코드가 컴파일되지만 런타임에 오류가 발생합니다.

치명적인 오류 : upperBound <lowerBound로 범위를 형성 할 수 없습니다.

1..5대신 사용할 수 있고 계산 j = 6 - i하여 j색인으로 사용할 수 있다는 것을 알고 있습니다 . 더 읽기 쉬운 것이 있는지 궁금합니다.


보기 내 대답 스위프트 3. 당신의 문제를 해결하기 위해 8 가지 방법까지 제공하는 비슷한 질문에 대한
Imanou 프티에게

답변:


184

최신 Swift 3 업데이트 (Swift 4에서도 작동)

reversed()범위 에서 방법을 사용할 수 있습니다.

for i in (1...5).reversed() { print(i) } // 5 4 3 2 1

또는 stride(from:through:by:)방법

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

stide(from:to:by:) 유사하지만 마지막 값을 제외합니다.

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

최신 Swift 2 업데이트

우선 프로토콜 확장 reverse은 사용 방법을 변경합니다 .

for i in (1...5).reverse() { print(i) } // 5 4 3 2 1

Stride는 Xcode 7 Beta 6에서 재 작업되었습니다. 새로운 사용법은 다음과 같습니다.

for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6
for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8

다음에서도 작동합니다 Doubles.

for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }

경계에 대한 부동 소수점 비교에주의하십시오.

Swift 1.2의 이전 편집 : Xcode 6 Beta 4부터 byReverseRange 는 더 이상 존재하지 않습니다.

범위를 반전하려는 경우에는 반전 기능 만 있으면됩니다.

for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1

0x7fffffff 에 의해 게시 된 바와 같이 임의의 정수로 반복하고 증가시키는 데 사용할 수 있는 새로운 stride 구조가 있습니다. 애플은 또한 부동 소수점 지원이 올 것이라고 밝혔다.

그의 답변에서 출처 :

for x in stride(from: 0, through: -8, by: -2) {
    println(x) // 0, -2, -4, -6, -8
}

for x in stride(from: 6, to: -2, by: -4) {
    println(x) // 6, 2
}

FYI Stride는 베타 6 이후 변경되었습니다
DogCoffee 2015 년

1
그것은해야한다 (1...5).reverse()(함수 호출로), 답변을 업데이트하십시오. (그것은 단지 두 글자입니다 때문에, 나는 귀하의 게시물을 편집 할 수 있습니다.)
Behdad

Swift 3.0-PREVIEW-4 (및 이전 버전)에서는 (1...5).reversed(). 또한에 대한 예제는 .stride()작동하지 않으며 stride(from:to:by:)대신 무료 기능이 필요합니다 .
davidA

2
strideswift 3 의 코드가 약간 잘못된 것 같습니다. 숫자 1을 포함하려면 다음 과 같이 through반대로 사용해야 to합니다.for i in stride(from:5,through:1,by:-1) { print(i) }
262Hz

4
reversedO (1)의 복잡성이 있다는 점을 지적 할 가치가 있습니다 . 원래 컬렉션을 래핑 할 뿐이며 빌드를 반복 할 필요가 없기 때문입니다.
devios1

21

이것의 비대칭에 문제가 있습니다.

for i in (1..<5).reverse()

... 이와 반대로 :

for i in 1..<5 {

역방향 범위를하고 싶을 때마다 괄호를 넣어야한다는 것을 기억해야 .reverse()하고, 끝에는 엄지 손가락처럼 튀어 나와서 써야합니다 . 이것은 대칭 적으로 카운트 업 및 카운트 다운하는 C 스타일 for 루프와 비교할 때 정말 추합니다. 그래서 대신 C 스타일 for 루프를 사용하는 경향이 있습니다. 그러나 Swift 2.2에서는 C 스타일 for 루프가 사라집니다! 그래서 저는 감소하는 모든 C 스타일 for 루프를이 추악한 .reverse()구조로 교체해야했습니다. 그동안 왜 역 거리 연산자가 없는지 궁금합니다.

하지만 기다려! 이것은 Swift입니다 — 우리는 우리 자신의 연산자를 정의 할 수 있습니다 !! 여기 있습니다 :

infix operator >>> {
    associativity none
    precedence 135
}

func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos)
    -> ReverseRandomAccessCollection<(Range<Pos>)> {
        return (start..<end).reverse()
}

이제 다음과 같이 말할 수 있습니다.

for i in 5>>>1 {print(i)} // 4, 3, 2, 1

이 커버 내 코드에서 발생하지만 그냥 가장 일반적인 경우 입니다 그것은 현재 모든 I 필요가 그래서, 단연코 가장 일반적인 경우.

운영자에게 일종의 내부 위기가 닥쳤습니다. 나는 >..의 반대 인을 ..<사용하고 싶었지만 그것은 합법적이지 않다. 점이 아닌 뒤에는 점을 사용할 수 없다. 나는 고려 ..>했지만 구별하기가 너무 어렵다고 결정했습니다 ..<. 좋은 점은 >>>" down to!" (물론 당신이 속한 다른 연산자로 올 무료하지만 내 조언은 다음과 같습니다. 슈퍼 대칭 정의 <<<무엇을해야 ..<합니까, 지금 당신은 가지고 <<<>>>. 입력하기 쉽고 대칭되는)


Swift 3 버전 (Xcode 8 seed 6) :

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
    ReversedRandomAccessCollection<CountableRange<Bound>> 
    where Bound : Comparable, Bound.Stride : Integer {
        return (minimum..<maximum).reversed()
}

Swift 4 버전 (Xcode 9 베타 3) :

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<CountableRange<Bound>>
    where Bound : Comparable & Strideable { 
        return (minimum..<maximum).reversed()
}

Swift 4.2 버전 (Xcode 10 베타 1) :

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedRandomAccessCollection<Range<Bound>>
    where Bound : Strideable { 
        return (minimum..<maximum).reversed()
}

Swift 5 버전 (Xcode 10.2.1) :

infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
    -> ReversedCollection<Range<Bound>>
    where Bound : Strideable {
        return (minimum..<maximum).reversed()
}

1
와, >>>운영자는 정말 멋지다! reverse()괄호로 묶인 표현의 끝에 붙는 것이 이상하게 느껴 지기 때문에 Swift 디자이너들이 그런 것에주의를 기울 였으면합니다. 프로토콜은 보폭이 양수인지 음수인지 파악하는 데 사용할 수 있는 완벽하게 합리적인 연산자를 제공 5>..0하기 때문에 자동으로 범위를 처리 할 수없는 이유가 없습니다 . ForwardIndexTypedistanceTo()
dasblinkenlight

1
덕분에 @dasblinkenlight - 내 애플 리케이션 중 하나에 내가했기 때문에이 내게 와서 많은 루프에 대한 신속한 C 스타일로 마이그레이션 현재 루프에 대한 C 스타일 때문에 변환해야한다고 (목표 - C에서) 루프에 대한 C의를 멀리 가고 있습니다. 이 루프는 내 앱 논리의 핵심을 나타내며 모든 것을 다시 작성하면 손상 될 위험이 있으므로 이는 단순히 끔찍했습니다. 따라서 저는 (주석 처리 된) C 스타일 표기법과 가능한 한 명확하게 일치하는 표기법을 원했습니다.
matt

산뜻한! 깨끗한 코드에 대한 집착이 마음에 듭니다!
Yohst

10

베타를 진행하면서이 질문에 대한 답변이 약간 변경된 것으로 보입니다. 베타 4 부터는 by()함수와 ReversedRange유형이 언어에서 제거되었습니다. 반전 된 범위를 만들려는 경우 옵션은 다음과 같습니다.

1 : 전방 범위를 생성 한 다음 reverse()기능을 사용하여 반전합니다.

for x in reverse(0 ... 4) {
    println(x) // 4, 3, 2, 1, 0
}

for x in reverse(0 ..< 4) {
    println(x) // 3, 2, 1, 0
}

2 : stride()베타 4에 추가 된 새 함수를 사용합니다 . 여기에는 시작 및 끝 인덱스와 반복 할 양을 지정하는 함수가 포함되어 있습니다.

for x in stride(from: 0, through: -8, by: -2) {
    println(x) // 0, -2, -4, -6, -8
}

for x in stride(from: 6, to: -2, by: -4) {
    println(x) // 6, 2
}

이 게시물에는 새로운 독점 범위 연산자도 포함되어 있습니다. ..로 대체되었습니다 ..<.

편집 : Xcode 6 베타 5 릴리스 노트 에서 Apple은이를 처리하기 위해 다음 제안을 추가했습니다.

ReverseRange가 제거되었습니다. lazy (x ..

여기에 예가 있습니다.

for i in lazy(0...5).reverse() {
    // 0, 1, 2, 3, 4, 5
}

+1 참조를 찾고 있는데 lazy(0....5).reverse()베타 5 릴리스 노트가 보이지 않습니다. 이 주제에 대한 다른 토론을 알고 있습니까? 또한 참고로, 해당 for루프 내부의 숫자 는 귀하의 예에서 거꾸로 표시됩니다.
Rob

1
@Rob Hmm 베타 릴리스 노트가 결국 삭제 될 것이라고 생각 했어야했습니다. 내가이 글을 썼을 때 lazy ()에 대한 참조를 본 유일한 곳 이었지만, 기꺼이 좀 더 살펴보고 나중에 집에 돌아 오면이를 업데이트 / 수정하겠습니다. 지적 해 주셔서 감사합니다.
Mick MacCallum 2014 년

1
@ 0x7fffffff 마지막 예에서 주석은 말하지만 // 0, 1, 2, 3, 4, 5실제로는 반대로해야합니다. 오해의 소지가있는 댓글입니다.
Pang

5

Xcode 7, 베타 2 :

for i in (1...5).reverse() {
  // do something
}

3

Swift 3, 4+ : 다음과 같이 할 수 있습니다.

for i in sequence(first: 10, next: {$0 - 1}) {

    guard i >= 0 else {
        break
    }
    print(i)
}

결과 : 10, 9, 8 ... 0

원하는 방식으로 사용자 정의 할 수 있습니다. 자세한 내용은 참조를 읽으십시오func sequence<T>


1

이것은 이것을하는 또 다른 방법 일 수 있습니다.

(1...5).reversed().forEach { print($0) }

-2

Reverse () 함수는 역 번호에 사용됩니다.

Var n : Int // 숫자 입력

i in 1 ... n.reverse () {Print (i)}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.