Kiedy używam pętli for w Playground, wszystko działało dobrze, dopóki nie zmieniłem pierwszego parametru pętli na najwyższą wartość. (iterowane w kolejności malejącej)
Czy to błąd? Czy ktoś jeszcze to miał?
for index in 510..509
{
var a = 10
}
Licznik wyświetlający liczbę iteracji, które zostaną wykonane, wciąż tyka ...
ios
swift
swift-playground
Krishnan
źródło
źródło
Odpowiedzi:
Xcode 6 beta 4 dodał dwie funkcje do iteracji zakresów z krokiem innym niż jeden:,
stride(from: to: by:)
który jest używany z zakresami wyłącznymi istride(from: through: by:)
, który jest używany z zakresami włączającymi.Aby wykonać iterację zakresu w odwrotnej kolejności, można ich użyć w następujący sposób:
Zauważ, że żadna z nich nie jest
Range
funkcją składową . Są to funkcje globalne, które zwracają aStrideTo
lubStrideThrough
struct, które są zdefiniowane inaczej niżRange
struct.Poprzednia wersja tej odpowiedzi korzystała z
by()
funkcji członkaRange
struktury, która została usunięta w wersji beta 4. Jeśli chcesz zobaczyć, jak to działało, sprawdź historię edycji.źródło
5.stride(to: 1, by: -1)
lub5.stride(through: 1, by: -1)
:
operatora, pośrednio iterując w dół, powodując, że ich pętle wykonują się, gdy sądzą, że przeskoczy nad nimi. Jest to bardzo wygodne do użytku interaktywnego, ale strasznie podatne na błędy w skryptach, do tego stopnia, że przewodniki stylu zalecają, aby go nie używać .Zastosuj funkcję wstecz do zakresu, aby iterować wstecz:
W przypadku Swift 1.2 i wcześniejszych:
Działa również z półotwartymi zakresami:
Uwaga:
reverse(1...10)
tworzy tablicę typu[Int]
, więc chociaż może to być dobre dla małych zakresów, rozsądnie byłoby użyć,lazy
jak pokazano poniżej lub rozważyć zaakceptowanąstride
odpowiedź, jeśli twój zakres jest duży.Aby uniknąć tworzenia dużej tablicy, użyj
lazy
wraz zreverse()
. Poniższy test działa skutecznie na placu zabaw, pokazując, że nie tworzy on tablicy z bilionemInt
s!Test:
W przypadku Swift 2.0 w Xcode 7:
Zauważ, że w Swift 2.0
(1...1_000_000_000_000).reverse()
jest typuReverseRandomAccessCollection<(Range<Int>)>
, więc działa dobrze:Dla Swift 3.0
reverse()
została zmieniona nareversed()
:źródło
reversed
może jednak skopiować kolekcję. Przynajmniej tak rozumiem dokumentacjęData
.Zaktualizowano dla Swift 3
Odpowiedź poniżej jest podsumowaniem dostępnych opcji. Wybierz ten, który najlepiej odpowiada Twoim potrzebom.
reversed
: liczby w zakresieNaprzód
Do tyłu
reversed
: elementy wSequenceType
Naprzód
Do tyłu
reversed
: elementy z indeksemCzasami potrzebny jest indeks podczas iteracji po kolekcji. Do tego możesz użyć
enumerate()
, który zwraca krotkę. Pierwszym elementem krotki jest indeks, a drugim elementem jest obiekt.Naprzód
Do tyłu
Zauważ, że jak zauważył Ben Lachman w swojej odpowiedzi , prawdopodobnie
.enumerated().reversed()
raczej chcesz to zrobić.reversed().enumerated()
(co spowodowałoby wzrost liczby indeksów).krok: liczby
Krok jest sposobem na iterację bez użycia zakresu. Istnieją dwie formy. Komentarze na końcu kodu pokazują, jaka byłaby wersja zakresu (przy założeniu, że wielkość przyrostu wynosi 1).
Naprzód
Do tyłu
Zmiana wielkości przyrostu na
-1
pozwala cofnąć się.Zauważ, że
to
ithrough
różnicę.stride: elementy SequenceType
Do przodu o 2
Używam
2
w tym przykładzie, aby pokazać inną możliwość.Do tyłu
Notatki
@matt ma ciekawe rozwiązanie, w którym definiuje swojego operatora odwrotnego i nazywa go
>>>
. Nie wymaga dużo kodu do zdefiniowania i jest używany w następujący sposób:Sprawdź, czy w stylu C nie ma pętli usuniętych z Swift 3
źródło
Swift 4 r
źródło
W Swift 5, w zależności od potrzeb, możesz wybrać jeden z nich czterech poniższych przykładów kodu placu zabaw , aby rozwiązać problem.
# 1. Za pomocą
ClosedRange
reversed()
metodyClosedRange
ma metodę o nazwiereversed()
.reversed()
Metoda ma następującą deklarację:Stosowanie:
Alternatywnie możesz użyć
Range
reversed()
metody:# 2. Za pomocą
sequence(first:next:)
funkcjiSwift Standard Library udostępnia funkcję o nazwie
sequence(first:next:)
.sequence(first:next:)
ma następującą deklarację:Stosowanie:
# 3. Za pomocą
stride(from:through:by:)
funkcjiSwift Standard Library udostępnia funkcję o nazwie
stride(from:through:by:)
.stride(from:through:by:)
ma następującą deklarację:Stosowanie:
Alternatywnie możesz użyć
stride(from:to:by:)
:# 4. Korzystanie z
AnyIterator
init(_:)
inicjalizatoraAnyIterator
ma inicjator o nazwieinit(_:)
.init(_:)
ma następującą deklarację:Stosowanie:
W razie potrzeby możesz zmienić poprzedni kod, tworząc metodę rozszerzenia
Int
i owijając w nim swój iterator:źródło
W przypadku wersji Swift 2.0 i nowszych należy zastosować odwrotność w zbiorze zakresu
Został przemianowany na .reversed () w Swift 3.0
źródło
W Swift 4 i późniejszych
źródło
Swift 4.0
Jeśli chcesz dołączyć
to
wartość:źródło
Jeśli ktoś chce iterować przez tablicę (
Array
lub bardziej ogólnie dowolnąSequenceType
) w odwrotnej kolejności. Masz kilka dodatkowych opcji.Najpierw możesz
reverse()
tablicę i przejść przez nią normalnie. Wolę jednak spędzaćenumerate()
dużo czasu, ponieważ wypisuje krotkę zawierającą obiekt i jego indeks.Należy tutaj zauważyć, że ważne jest, aby wywoływać je w odpowiedniej kolejności:
for (index, element) in array.enumerate().reverse()
zwraca indeksy w kolejności malejącej (czego zwykle oczekuję). natomiast:
for (index, element) in array.reverse().enumerate()
(co jest bardziej zbliżone do NSArray'sreverseEnumerator
)przesuwa tablicę do tyłu, ale wyświetla indeksy rosnące.
źródło
jak w Swift 2.2, Xcode 7.3 (10, czerwiec 2016):
Wynik :
źródło
Zamiast tego możesz rozważyć użycie
while
pętli w stylu C. Działa to dobrze w Swift 3:źródło
Możesz użyć metody reverse (), aby łatwo odwrócić wartości.
Metoda reverse () odwraca wartości.
źródło
źródło