Playgroundでforループを使用すると、forループの最初のパラメーターを最高値に変更するまで、すべてが正常に機能しました。(降順で反復)
これはバグですか?他に誰か持っていましたか?
for index in 510..509
{
var a = 10
}
実行される反復の数を表示するカウンターは、刻々と過ぎます...
Playgroundでforループを使用すると、forループの最初のパラメーターを最高値に変更するまで、すべてが正常に機能しました。(降順で反復)
これはバグですか?他に誰か持っていましたか?
for index in 510..509
{
var a = 10
}
実行される反復の数を表示するカウンターは、刻々と過ぎます...
回答:
:Xcodeの6ベータ4は、1つの以外のステップと範囲に反復するために2つの機能を追加し
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
メンバー関数ではないことに注意してください。これらは、a StrideTo
またはStrideThrough
struct を返すグローバル関数であり、structとは定義が異なりRange
ます。
この回答の以前のバージョンは、ベータ4で削除されby()
たRange
構造体のメンバー関数を使用していました。それがどのように機能したかを確認したい場合は、編集履歴を確認してください。
5.stride(to: 1, by: -1)
または5.stride(through: 1, by: -1)
:
暗黙的に下方向に反復する演算子によってつまずかれ、ループをスキップすると思ったときにループを実行させることがよくあるとは言えません。インタラクティブな使用には非常に便利ですが、スクリプトでエラーが発生しやすく、スタイルガイドが推奨するほどのエラーになります。
逆関数を範囲に適用して、逆方向に反復します。
用スウィフト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()
ます。次のテストはPlaygroundで効率的に実行され、1兆Int
秒の配列を作成していないことを示しています。
テスト:
var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
if ++count > 5 {
break
}
println(i)
}
Xcode 7のSwift 2.0の場合:
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
}
reversed
ただし、コレクションをコピーできます。少なくとも、それが私がのドキュメントを理解する方法Data
です。
Swift 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()
は、タプルを返すを使用できます。タプルの最初の要素はインデックスで、2番目の要素はオブジェクトです。
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()
。
ストライドは、範囲を使用せずに反復する方法です。2つの形式があります。コードの最後にあるコメントは、範囲バージョンがどうなるかを示しています(増分サイズが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
@mattには興味深いソリューションがあり、彼は独自の逆演算子を定義して呼び出します>>>
。定義に多くのコードを必要とせず、次のように使用されます。
for index in 5>>>0 {
print(index)
}
// 4
// 3
// 2
// 1
// 0
Swift 5では、必要に応じて、問題を解決するために、次の4つのPlaygroundコード例のいずれかを選択できます。
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
*/
sequence(first:next:)
関数の使用Swift標準ライブラリには、という関数が用意されてい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標準ライブラリには、という関数が用意されてい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
*/
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
*/
配列(Array
またはより一般的にはany SequenceType
)を逆に反復処理したい場合。追加のオプションがいくつかあります。
最初にreverse()
、配列を作成し、通常どおりにループすることができます。ただしenumerate()
、オブジェクトとインデックスを含むタプルを出力するため、私は多くの時間を使用することを好みます。
ここで注意すべきことの1つは、これらを正しい順序で呼び出すことが重要であることです。
for (index, element) in array.enumerate().reverse()
インデックスを降順で生成します(これは私が通常期待するものです)。一方:
for (index, element) in array.reverse().enumerate()
(これはNSArrayのより近い一致ですreverseEnumerator
)
配列を逆方向にたどりますが、昇順のインデックスを出力します。
Swift 2.2、Xcode 7.3(10、June、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
値を簡単に反転するには、reversed()メソッドを使用できます。
var i:Int
for i in 1..10.reversed() {
print(i)
}
reverse()メソッドは値を逆にします。