Czy istnieje sposób pracy z odwróconymi zakresami w Swift?
Na przykład:
for i in 5...1 {
// do something
}
jest nieskończoną pętlą.
W nowszych wersjach Swifta ten kod kompiluje się, ale w czasie wykonywania wyświetla błąd:
Błąd krytyczny: nie można utworzyć zakresu z upperBound <lowerBound
Wiem, że mogę 1..5
zamiast tego używać , obliczać j = 6 - i
i używać j
jako mojego indeksu. Zastanawiałem się tylko, czy jest coś bardziej czytelnego?
Odpowiedzi:
Aktualizacja dla najnowszego Swift 3 (nadal działa w Swift 4)
Możesz użyć tej
reversed()
metody na zakresieAlbo
stride(from:through:by:)
metodastide(from:to:by:)
jest podobny, ale wyklucza ostatnią wartośćAktualizacja dla najnowszego Swift 2
Przede wszystkim rozszerzenia protokołów zmieniają sposób
reverse
użycia:for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
Stride został przerobiony w Xcode 7 Beta 6. Nowe użycie to:
Działa również w przypadku
Doubles
:Uważaj na porównania zmiennoprzecinkowe tutaj dla granic.
Wcześniejsza edycja dla Swift 1.2 : od Xcode 6 Beta 4, by i ReverseRange już nie istnieją: [
Jeśli chcesz tylko odwrócić zakres, wystarczy funkcja reverse :
Jak napisano w 0x7fffffff, istnieje nowa konstrukcja stride, której można użyć do iteracji i inkrementacji przez dowolne liczby całkowite. Apple stwierdził również, że nadchodzi obsługa zmiennoprzecinkowych.
Pochodzi z jego odpowiedzi:
źródło
(1...5).reverse()
(jako wywołanie funkcji), zaktualizuj swoją odpowiedź. (Ponieważ to tylko dwie postacie, nie mogłem edytować twojego postu.)(1...5).reversed()
. Ponadto przykład dla.stride()
nie działa istride(from:to:by:)
zamiast tego potrzebuje bezpłatnej funkcji .stride
kod języka Swift 3 jest nieco niepoprawny. aby uwzględnić liczbę 1, należy użyć wthrough
przeciwieństwie doto
tego:for i in stride(from:5,through:1,by:-1) { print(i) }
reversed
ma złożoność O (1), ponieważ po prostu otacza oryginalną kolekcję i nie wymaga iteracji, aby ją zbudować.Jest coś niepokojącego w asymetrii tego:
... w przeciwieństwie do tego:
Oznacza to, że za każdym razem, gdy chcę zrobić odwrócony zakres, muszę pamiętać o umieszczeniu nawiasów, a dodatkowo muszę to napisać
.reverse()
na końcu, wystając jak bolący kciuk. Jest to naprawdę brzydkie w porównaniu do pętli w stylu C, które są symetryczne zliczaniem w górę i w dół. Więc zamiast tego używałam pętli w stylu C. Ale w Swift 2.2, pętle w stylu C odchodzą! Więc musiałem się pospieszyć, zastępując wszystkie moje dekrementujące pętle w stylu C dla tej brzydkiej.reverse()
konstrukcji - zastanawiając się przez cały czas, dlaczego u licha nie ma operatora odwrotnego zasięgu?Ale poczekaj! To jest Swift - wolno nam definiować własnych operatorów !! No to ruszamy:
Więc teraz mogę powiedzieć:
Obejmuje to tylko najczęstszy przypadek, który występuje w moim kodzie, ale jest to zdecydowanie najczęstszy przypadek, więc to wszystko, czego obecnie potrzebuję.
Miałem pewnego rodzaju wewnętrzny kryzys, który zbliżał się do operatora. Chciałbym użyć
>..
, jako odwrotności..<
, ale to nie jest legalne: wydaje się, że nie można używać kropki po nie-kropce. Rozważałem,..>
ale zdecydowałem, że to zbyt trudne do odróżnienia..<
. Fajną rzeczą>>>
jest to, że krzyczy na ciebie: „na dół !” (Oczywiście możesz wymyślić inny operator. Ale moja rada jest taka: aby uzyskać super symetrię, zdefiniuj<<<
, co..<
robi, a teraz masz<<<
i>>>
które są symetryczne i łatwe do wpisania.)Wersja Swift 3 (Xcode 8 seed 6):
Wersja Swift 4 (Xcode 9 beta 3):
Wersja Swift 4.2 (Xcode 10 beta 1):
Wersja Swift 5 (Xcode 10.2.1):
źródło
>>>
operator jest naprawdę fajny! Mam nadzieję, że projektanci Swift zwracają uwagę na takie rzeczy, ponieważ trzymaniereverse()
się końcówek wyrażeń w nawiasach wydaje się dziwne. Nie ma powodu, dla którego nie mogliby5>..0
automatycznie zajmować się zakresami, ponieważForwardIndexType
protokół zapewnia całkowicie rozsądnydistanceTo()
operator, którego można użyć do ustalenia, czy krok powinien być dodatni czy ujemny.Wygląda na to, że odpowiedzi na to pytanie nieco się zmieniły, gdy przechodziliśmy przez wersje beta. Od wersji beta 4 zarówno
by()
funkcja , jak iReversedRange
typ zostały usunięte z języka. Jeśli chcesz uzyskać odwrócony zakres, masz teraz następujące opcje:1: Utwórz zakres do przodu, a następnie użyj
reverse()
funkcji, aby go odwrócić.2: Skorzystaj z nowych
stride()
funkcji, które zostały dodane w wersji beta 4, w tym funkcji do określania indeksów początkowych i końcowych, a także ilości do iteracji.Zauważ, że w tym poście umieściłem również nowego operatora zakresu wyłącznego.
..
został zastąpiony..<
.Edycja: z informacji o wersji Xcode 6 beta 5 firma Apple dodała następującą sugestię dotyczącą rozwiązania tego problemu:
Oto przykład.
źródło
lazy(0....5).reverse()
i nie widzę informacji o wersji beta 5. Czy znasz inne dyskusje na ten temat? Ponadto, do Twojej wiadomości, liczby w tejfor
pętli są w twoim przykładzie odwrócone.// 0, 1, 2, 3, 4, 5
ale w rzeczywistości powinien zostać odwrócony. Komentarz jest mylący.Xcode 7, beta 2:
źródło
Swift 3, 4+ : możesz to zrobić w ten sposób:
wynik : 10, 9, 8 ... 0
Możesz go dostosować w dowolny sposób. Aby uzyskać więcej informacji, przeczytaj
func sequence<T>
odniesienieźródło
To mógłby być inny sposób na zrobienie tego.
źródło
Funkcja Reverse () służy do odwrócenia liczby.
Var n: Int // Wpisz liczbę
For i in 1 ... n.reverse () {Print (i)}
źródło