iPhone アプリを自分でつくる 5.
今回の内容: コレクション型(配列、辞書、Set)、 条件式、 ループ について
まずコレクション型の配列についてみていきます。
なおコレクション型というのは複数の要素をひとまとめにしたもので、Collection型の機能を持つものです。
配列について
配列はArray アレイとも言い、数字や文字をひとまとまりにしたものです。
・作り方は、内容を[ ] 四角カッコで囲んで、, 内容をカンマ記号で区切ります。
・内容の一つ一つをElement エレメント(要素)と呼びます。
・Element は、それぞれの順番が保存され内部で Indexがつけられます。
・Index は、0から始まる整数です。
・Index を使用して要素を取り出すことができます。
・要素は追加、削除ができます。
・空(カラ)の配列を作ることができます。
配列の作成
let flowers: [String] = ["Sakura", "Ume", "Kiku"]
let points: [Int] = [100, 92, 63]
var time: [Double] = [ 10.3, 9.1, 9.5]
var name = ["田中", "鈴木"] // 型を明示せずに型推論[String]をシステムにまかせるシンプルな書き方
// 定義で書かれる記法
var stations3: Array<String> = ["Tokyo", "Shinagawa", "Yokohama"] // 型を明記した書き方 公式な内容でよく使われる形
var num: Array<Int> = Array([1, 3, 5]) // 定義通りに書くとこうなると思いますが、あまり見たことありません。
print(num)
空の配列をつくることもできます。要素がある場合と同じように扱うことができるのでよく使われます。
var playerPoints: [Int] = [] // 型を[Int]でしておき、空の配列は[]で表す方法
var systemPoints = [Double]() // 変数では型を明示せずに [型]() で空の配列を表す方法
// 定義で書かれる記法
let testEmpty: Array<Double> = []
var emptyStrings: Array<String> = Array()
上記の例で[Double]() やArray()の最後にある()はイニシャライズ(初期化:使えるようにする)ためのものです。
配列はいろいろな書き方ができるので混乱してしまいがちですが、自分の書き方を決めておいて、他のコードを見たときに配列だと理解できれば良いです。
なお定義として載せた書き方は、一般に書くことはあまりないですが、公式ドキュメントなどで見たときに配列なんだな、とわかれば十分だと思います。
ちなみに、各型の書き方のことをliteral リテラルと呼び、定義とは違うやさしい書き方をプログラミングではシンタックスシュガー(systax sugar): 糖衣構文 と呼びます。糖衣というのは、昔よく使った「オブラート」ですね。
今でもオブラートは使われているのでしょうか?
配列のエレメントを繰り返してつくる際には便利な方法があります。
配列の要素を繰り返しできたら良いのにな〜と思ったときには、この機能があったことを忘れている、という経験は私だけではないはずです。
var digitCounts = Array(repeating: 0, count: 10)
print(digitCounts)
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
いろいろな要素を持つ配列
IntやDoubleなど基本的な型はもちろんですが、自分で作った構造体を型として扱うことも通常に行います。
let myNumbers: [Int] = [3, 5, 9, 1, 6]
let myDoubles: Array<Double> = [2.3, 9.6, 100.9, 1.5]
var myFriends: [MyFriend] = [friend1, friend2, friend3 ]
// 自分でMyFriend型の構造体をつくって、データを配列に入れておくイメージ
// friend1, friend2 … にそれぞれ名前、住所が入っていて取り出すことができるようなイメージ。
// 今後アプリを作る際にこのような使い方をしていきます。
配列の要素の取り出し
配列のIndexを[ ]で指定するとその要素を返すことができる。
var stations = ["Tokyo", "Shinagawa", "Yokohama"]
print(stations[0]) // Tokyo
print(["Tokyo", "Shinagawa", "Yokohama"][1]) // Shinagawa
// アプリでこのような使い方はあまりしませんが、配列に直接Index指定しても要素が返ります。
配列の要素を最後に追加
.append(要素)で要素を配列の最後に追加できる。
stations.append("Odawara")
print(stations) // ["Tokyo", "Shinagawa", "Yokohama", "Odawara"]
配列の要素を挿入
.insert(at: 要素)で要素を指定場所に挿入できる。
stations.insert("Ekiben", at: 3)
print(stations) // ["Tokyo", "Shinagawa", "Yokohama", "Ekiben", "Odawara"]
// at: 3 で Index3 の前に入る
配列の要素を削除
.remove(at: 要素)で指定場所の要素を削除できる。
.removeLast() で最後の要素を削除できる。
.removeFirst() で最初の要素を削除できる。
.removeAll() で全て削除。
stations.remove(at: 1) // index 1番(2つ目)の要素”Shinagawa”を削除した
print(stations) // ["Tokyo", "Yokohama", "Ekiben", "Odawara"]
stations.removeLast()
print(stations) // ["Tokyo", "Yokohama", "Ekiben"]
stations.removeFirst()
print(stations) // ["Yokohama", "Ekiben"]
stations.removeAll()
print(stations) // [] 空の配列
配列に配列を追加する
配列に要素そのものを加えるときとは違うので注意
.append(contentsOf: 配列) で配列を加えることができる。
配列 + 配列 のように + 記号で配列同士をひとつにまとめることもできる。
ここらあたりの話はご自分でも何かの配列を作ってみると理解しやすいかと思います。
stations = []
let stationsA = ["Tokyo", "Shinagawa"]
let stationsB = ["Yokohama", "Odawara"]
stations.append(contentsOf: stationsA)
stations.append(contentsOf: stationsB)
print(stations) // ["Tokyo", "Shinagawa", "Yokohama", "Odawara"]
stations = stations + ["Atami", "Mishima"]
print(stations) // ["Tokyo", "Shinagawa", "Yokohama", "Odawara", "Atami", "Mishima"]
要素が配列型の配列(2次元配列)
配列の要素は、Int型、String型などと同様Array<String>型など配列を持つことができる。
型を明記するときは、[[String]] のようになる。
このように要素が配列の場合を特に2次元配列と呼ぶ。(要素が2次元配列であれば3次元配列となる)
var row1 = ["A1", "B1", "C1"]
var row2 = ["A2", "B2", "C2"]
var row3 = ["A3", "B3", "C3"]
var board: [[String]] = [] // 空の1次元配列をつくっておく
board.append(row1) // 配列ごとappend(配列)している。
board.append(row2)
board.append(row3)
print(board)
// ----------------------------
// [["A1", "B1", "C1"], ["A2", "B2", "C2"], ["A3", "B3", "C3"]]
// 2次元配列を理解しやすいように、このような記入をする場合も多い
var myGameBoard = [
["A1", "B1", "C1"],
["A2", "B2", "C2"],
["A3", "B3", "C3"]
]
上記では、空の一次元配列[ ]をつくったあとで、 board.append(row1) のように配列に直接配列をappend して2次元配列をつくっています。
配列の要素を数える
配列の要素数を調べるには .count を使用する。
.count は配列構造体のプロパティ(struct Arrayの持つ変数)です。
var totalStations = stations.count
print(totalStations) // 6
ある要素を含んでいるかどうか確認する
配列.contains(調べる要素) とするとBool型が返ります。
var isTokaidoLine = stations.contains("Hakodate")
print(isTokaidoLine) // false
配列のソート
ソートする には .sorted() で、ソートされた配列を変数に返します。
ソートを逆にする には .reversed() を使用して変数に返します。
let names = ["Suzuki", "Tanaka", "Sato", "Hayashi", "Honda"]
var sortedNames = names.sorted()
print(sortedNames) // ["Hayashi", "Honda", "Sato", "Suzuki", "Tanaka"]
var reversedNames = sortedNames.reversed()
print(reversedNames)
// ReversedCollection<Array<String>>(_base: ["Hayashi", "Honda", "Sato", "Suzuki", "Tanaka"])
配列自体をソートするには .sort() を使用します。
var myFavorite = ["Nikuman", "Amman", "Gyoza", "Ramen", "Gyudon"]
myFavorite.sort()
print(myFavorite) // ["Amman", "Gyoza", "Gyudon", "Nikuman", "Ramen"]
配列型に内容が入っているか確認する
.isEmpty は配列に内容がないかあるかを Bool型で返します。なければ trueを返します。
let testEmpty1: [Int] = []
let isEmptyCheck = testEmpty1.isEmpty
print(isEmptyCheck) // true
辞書型について
辞書型は下記のようにつくります。
let itemPrices: [String: Int] = ["Apples": 250, "Oranges": 150, "Bananas": 200]
var bananaPrice = itemPrices["Bananas"]
print(bananaPrice)
// コンソール表示
Optional(200)
[ ]四角カッコの中にKey キーと Value バリューを : コロンで一対にしたものを配置していきます。
左側がキーで右側がバリューとなります。
辞書内でのペアが崩れることはありませんが、ペアの順番は保持されません。
キーとバリューの型は違っていても問題ありませんが、キーとして型は揃えて、またバリューでも型を揃えておきます。
キーの重複はエラーとなります。バリューは重複しても問題ありません。
itemPrices["Bananas"] のように変数辞書[キー] とすることでオプショナル型のバリューが返ってきます。もしキーの値が見つからなかった場合にクラッシュしないように(Swift制作の方がたが)オプショナル型で返す設定にしていると思われます。(配列についてはオプショナル型ではありません。配列で設定ミスするとクラッシュしてしまいます。)
下のように探索時にキーの答えが見つからなかった場合のDefault を設定しておく方法もあります。(defaultバリューは、Value と型を揃える必要はあります。)
var mangoPrice = itemPrices["Mangoes", default: 500]
print(mangoPrice)
// コンソール表示
500
空の辞書を作っておいて、追加していくことも可能です。
追加するには辞書[キー] = バリューのようにします。
var pets = [String: String]() // 空の辞書型を作成
pets["Tama"] = "cat" // キー Tama の辞書を作成
pets["Taro"] = "dog" // キー Taro の辞書を作成
print(pets)
// コンソール表示
["Tama": "cat", "Taro": "dog"]
上記では入力した順番に反映されていますが、この順番は変わる可能性があります。
辞書を書き換えるにはキーの内容を上書きします。
pets["Tama"] = "rabbit"
print(pets)
// コンソール表示
["Tama": "rabbit", "Taro": "dog"] // "Tama"が ラビットになってしまった!
順番は変わる可能性がありますが、ループ処理を行い内容を確認することができます。(ループ処理の方法はこの後でご紹介します。)
let imageItems = ["star": "star.jpg",
"mountain": "mountain.jpg",
"sea": "sea.jpg"]
for (name, item) in imageItems {
print("The Image of '\(name)' is '\(item)'.")
}
Set型について
Set型 セット型は配列とよく似ていますが、順番が保持されません。
Set型は配列とよく似ていますが、重複しません。重複を見つけると自動的に排除します。
作り方は下記のようになります。
let stations: Set = ["Tokyo", "Shinagawa", "Shin Yokohama"]
print(stations)
var morningSet = Set(["Coffee", "Toast", "Egg sand", "Salad", "Miso-soup"])
print(morningSet)
// コンソール表示 順番が変わって表示されます。
["Shinagawa", "Shin Yokohama", "Tokyo"]
["Salad", "Coffee", "Miso-soup", "Toast", "Egg sand"]
Setも記入方法がいくつかあるので、自分の方法を決めておくと良いかと思います。
順番は変わる可能性がありますが、ループ処理で内容を確認することができます。
(ループ処理の方法はこの後でご紹介します。)
var primes: Set = [2, 3, 5, 7]
for number in primes {
print(number)
}
// コンソール表示 順番が変わった
2
7
5
3
空のSet は下記のようになります。
var testSet1: Set<Int> = []
print(testSet1)
var testSet2 = Set<String>()
print(testSet2)
// 私はいまだに空セットが覚えられません でもあなたなら大丈夫です!
Set には順番がないのでArray の .append() はありません。.insert() を使用して追加します。
var lunchSet: Set<String> = []
lunchSet.insert("Ramen")
lunchSet.insert("Chahan")
lunchSet.insert("Gyoza")
print(lunchSet)
// コンソール表示
["Chahan", "Gyoza", "Ramen"]
配列に重複の可能性がある場合、Setをはさんで排除することができます。
var myDinner: Array = ["egg", "soup", "fish", "egg", "hijiki", "fish"]
var checkDinner = Set(myDinner) // Set で重複を排除
var myCheckedDinner = Array(checkDinner) // 配列での作業をしたいのでArrayに戻した
print(myCheckedDinner)
// コンソール表示
["egg", "fish", "soup", "hijiki"]
条件分岐について
プログラムの途中で何らかの変数が変わったとき、その変わった状態で次に進む内容を変化させることを条件分岐と言います。
条件分岐の種類
if 〜 : 〜であれば・・・する。(else その他の場合・・・する。)
guard 〜: 〜でなければ、else・・・する。〜であれば・・・する。
(falseの場合に先にelseで対応を除外しておく)
switch : 条件が細かく分かれるときに、ケース毎に返す値をセットする。
ケースはすべての場合を網羅する必要がある。
三項演算子:if文と同じ内容を1行にシンプルにまとめられる。
しかし複雑な条件の場合は読み難くなる。
いろいろな条件分岐方法
ケース
本のページ数:bookPages を読書日数:readDays で割って平均読書ページを出しています。これはまだ条件分岐はしていません。
var bookPages = 350
var readDays = 12
var avgPerDay = 0
avgPerDay = bookPages / readDays
print(avgPerDay)
//---------------------------------
29 Int での計算のため回答もIntとなる
しかし読書日数を0日とすると 0で割り算をするためエラーとなる。
var bookPages = 350
var readDays = 0
var avgPerDay = 0
avgPerDay = bookPages / readDays
//----------------------------------
x error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
・読書日数が0日のときもエラーが立たないように条件分岐をおこないます。
if で条件分岐を行なってみます。
var bookPages = 350
var readDays = 0
var avgPerDay = 0
if readDays > 0 {
avgPerDay = bookPages / readDays // readDays が0より大きい時計算する
} else {
avgPerDay = 0 // readDays が0以下の場合は0を代入する
}
print(avgPerDay)
// -------------------------------------
0
次も if での条件分岐ですが、最初にエラー発生を排除する順番にした条件分岐です
var bookPages = 350
var readDays = 0
var avgPerDay = 0
if readDays <= 0 {
avgPerDay = 0 // readDays が0以下の場合は 0を代入する
} else {
avgPerDay = bookPages / readDays // readDays が0より大きい場合に計算する
}
print(avgPerDay)
// -------------------------------------
0
次は switch を使ってみます。
0より大きいか、0 以下であるか の2択の問題なのでこの場合switch を使うメリットは感じにくいです。
switch の条件分岐を 1以上とdefaultの2種類としました。(すべてのケースを網羅する形にする必要があるため、残りのケースをdefaultとしています。)
var bookPages = 350
var readDays = 0
var avgPerDay = 0
switch readDays {
case 1...Int.max : // 1以上Intの最大値までをひとつの条件区分にしました
avgPerDay = bookPages / readDays
default :
avgPerDay = 0 // 最初のcase に当てはまらない場合は 0を代入します。
}
print(avgPerDay)
// -------------------------------------
0
次は三項演算子を使ってみます。
三項演算子は1行で条件分岐ができる便利なものです。
ただし複雑な条件分岐になると読みにくさの問題が発生します。
三項演算子の書き方は
・ 変数 = 条件 ? 真の場合に返す内容 : 偽の場合に返す内容
となります。
今回は単純な条件で Yes / No の2択、 回答もシンプルで読みにくさの問題はありません。
・条件は (readDays > 0)
・真の時は (bookPages / readDays)
・偽の時は 0
で分岐させています。
var bookPages = 350
var readDays = 0
var avgPerDay = 0
avgPerDay = (readDays > 0) ? (bookPages / readDays) : 0
print(avgPerDay)
// -------------------------------------
0
// 条件は(readDays > 0)
// 真のときに返す内容は (bookPages / readDays)
// 偽のときに返す内容は 0
次は guard 文で書いて見ます。
guard 文の書き方は
・ guard 条件式 else { 条件にあてはまらない時に実行する内容 }
条件式に適合した場合に実行する内容
関数func()を使用していますが内側のguard に注目してください。
guard days > 0 の条件が必要だけれども成り立たない場合は0を返す、成り立つのであれば次の式を計算する、という条件分岐です。
guard文は嫌な条件から早めに退出する方法です。
var bookPages = 350
var readDays = 0
var avgPerDay = 0
func readResult(pages: Int, days: Int, perDay: Int) -> Int {
guard days > 0 else { // days > 0 が成り立たない時
return 0 // 0を返す
}
return pages / days // days > 0 が成り立つときに計算する
}
avgPerDay = readResult(pages: bookPages, days: readDays, perDay: avgPerDay)
print(avgPerDay)
上の例では readResult が 関数名となり、3つの変数Intを受け取りIntを返す設定にしています。
最後にreadResult(pages: bookPages, days: readDays, perDay: avgPerDay) を
実行して、変数 avgPerDay に代入しています。
関数については後ほど行います。
ループ文(for in文、 while文)
ループは繰り返し処理のことで、コンピュータが得意とする作業です。
普通のパソコンでも単純な計算式であれば1秒間に何億回もの計算を行なってくれます。
プログラムの論理の流れをつくっているアルゴリズムは①順次②選択③繰り返し、の3つの制御構造の組み合わせでできていると言われますが、ループ文は繰り返しを担う大事な役割をもっています。
forループ
forループは配列 やDictionary型、または 0…10などの設定範囲を最初から順番に取り出しては処理することを繰り返します。
let stations = ["Tokyo", "Shinagawa", "Yokohama", "Odawara", "Atami"]
for station in stations {
print("Next stop is \(station)")
}
//----------------------------------------
//Next stop is Tokyo
//Next stop is Shinagawa
//Next stop is Yokohama
//Next stop is Odawara
//Next stop is Atami
上の例で for station とありますが、この名前はなんでもよく、このforループの中でだけ使える一時的な変数です。
つまり for s in stations { でもよいですが、変数をstation にすることで、
print("Next stop is \(station)") のように使うことができ読みやすいコードとなります。
上の例で in stations とありますが、これが配列を持つ定数 stations で、
print("Next stop is \(station)") がループ本体(loop body)で繰り返し実行されるものです。
配列を使用した forループでは、配列の最初(Index: 0)から順にElement を変数に代入してループ本体の処理をしたら次のIndex を取り出します。
そして最後の値を取り出して処理したらループを終了します。
変数stationは作られては実行後に捨てられることを繰り返します。
上の例と同じ内容を0から始まる数値を利用して書きます。
let stations = ["Tokyo", "Shinagawa", "Yokohama", "Odawara", "Atami"]
for i in 0..<stations.count {
print("Next stop is \(stations[i])")
}
//----------------------------------------
//Next stop is Tokyo
//Next stop is Shinagawa
//Next stop is Yokohama
//Next stop is Odawara
//Next stop is Atami
繰り返しの範囲を0からにすると、都合よく配列のIndex に合致します。
ループ変数をi として繰り返し範囲を0から4までの5回とします。
最後のIndexである4は Array.count - 1 なので、範囲は 0..<Array.count と表現できます。
上の例での for ループの動きのイメージ
(1) for に続くi に0..<stations.count が順に代入されます。
最初は i に0が代入される。
ループ本体では stations[0] として配列stationsのIndex 0番が使われる。
print("Next stop is \(stations[0])")の実行が終わると 変数i はクリアされ
る。
(2) i に1が代入され print("Next stop is \(stations[1])")が実行され終わるとクリ
アされる。
続いてi = 2, i = 3, i =4 が代入され、それぞれループ本体が実行されてはクリア
される。
(3) i に5が代入されると 0..<stations.count の条件を満たさないのでforループの
実行をストップして、そのあとのコードに移動する。
今までの例だと、出力される文字が同じでしたので、条件分岐を入れて最初の駅と最後の駅は違うアナウンスにしてみましょう。
let stations = ["Tokyo", "Shinagawa", "Yokohama", "Odawara", "Atami"]
for i in 0..<stations.count {
if i == 0 {
print("This train is bound for \(stations[stations.count - 1]) from \(stations[0])")
} else if i == (stations.count - 1) {
print("We will arrive at \(stations[stations.count - 1]) in a few minutes")
} else {
print("Next stop is \(stations[i])")
}
}
//This train is bound for Atami from Tokyo
//Next stop is Shinagawa
//Next stop is Yokohama
//Next stop is Odawara
//We will arrive at Atami in a few minutes
最初の駅は Index: 0、最後の駅は Index: (stations.count - 1 ) なので、i がこの値になったときだけアナウンスを変えています。
新幹線の自動アナウンスもこれと同じような条件分岐のプログラムが使われていると思います。知りませんけど。。。
九九の掛け算の一の段を出力する
ループ変数 i に範囲1…9が順番に入る
for i in 1...9 {
print("1 x \(i) = \(1 * i)")
}
// 1 x 1 = 1
// 1 x 2 = 2
// 1 x 3 = 3
// 1 x 4 = 4
// 1 x 5 = 5
// 1 x 6 = 6
// 1 x 7 = 7
// 1 x 8 = 8
// 1 x 9 = 9
九九の掛け算の一の段から九の段までを出力する
2重ループを使用します
ループの動きのイメージ
(1) ループ変数 i に 1 が入る。
(2) ループ変数 j に 範囲1…9が順に入る。
(3) ループ変数 i に 2 が入る。
(4) ループ変数 j に 範囲1…9が順に入る。
(5) ループ変数 i に 3が入る。
~ ~ ~ 省略 ~ ~ ~
(6) ループ変数 i に 9 が入る。
(7) ループ変数 j に 範囲1…9が順に入る。
つまり内側のj のループが1セット終わると次の外側のi のループがひとつ進む、というような動きをします。
for i in 1...9 {
for j in 1...9 {
print("\(i) x \(j) = \(i * j)")
}
print(" -*-*-")
}
// 1 x 1 = 1
// 1 x 2 = 2
// 1 x 3 = 3
// 1 x 4 = 4
// 1 x 5 = 5
// 1 x 6 = 6
// 1 x 7 = 7
// 1 x 8 = 8
// 1 x 9 = 9
// -*-*-
// 2 x 1 = 2
// 〜〜〜省略〜〜〜
// 8 x 9 = 72
// -*-*-
// 9 x 1 = 9
// 9 x 2 = 18
// 9 x 3 = 27
// 9 x 4 = 36
// 9 x 5 = 45
// 9 x 6 = 54
// 9 x 7 = 63
// 9 x 8 = 72
// 9 x 9 = 81
// -*-*-
盤面のマスの名前のように出力を調整する
print()の使い方で出力が盤面状になるようにしています。
print("内容", terminator: " ") の terminator: " " で " "の中にある文字(スペース)を区切り文字として横並びに出力しています。
内側のj が1セット終わるとprint("")が実行されてから 外側 iがひとつ進みます。
print("") ではterminatorは使用していないので、縦に移動します。
let boardRow = ["A", "B", "C", "D", "E", "F", "G", "H"]
let boardColumn = ["1", "2", "3", "4", "5", "6", "7", "8"]
for i in 0..<8 {
for j in 0..<8 {
print("\(boardRow[j])\(boardColumn[i])", terminator: " ")
}
print("")
}
// A1 B1 C1 D1 E1 F1 G1 H1
// A2 B2 C2 D2 E2 F2 G2 H2
// A3 B3 C3 D3 E3 F3 G3 H3
// A4 B4 C4 D4 E4 F4 G4 H4
// A5 B5 C5 D5 E5 F5 G5 H5
// A6 B6 C6 D6 E6 F6 G6 H6
// A7 B7 C7 D7 E7 F7 G7 H7
// A8 B8 C8 D8 E8 F8 G8 H8
ループ内で変数を必要としない場合はアンダーバーを使用します。
// 変数を必要としないループ (変数は使わず回数を重ねたい)
var shake = "Shake, shake"
for _ in 1...3 { // i などの代わりに _ アンダーバーをセット
shake += ", shake"
}
print(shake)
// コンソール表示
Shake, shake, shake, shake, shake
2次元配列を出力する
for文を入れ子にすると2次元配列の内容を取得するのに都合がよいです。
下の例では、2次元配列の変数をmyBoardとしています。
(1) for row in myBoard の row に myBoard の1つ目の要素(配列)が入ります。
(2) for col in row のcol に (1)で取り出したrow(配列)の1つ目の要素
(String: "A1")が入ります。
(3) for col in row のcol に (1)で取り出したrow(配列)の2つ目の要素
(String: "B1")が入ります。
〜〜〜 同じように続く〜〜〜
(4) for col in row のcol に (1)で取り出したrow(配列)の8つ目の要素
(String: "H1")が入ります。
(5) for row in myBoard の row に myBoard の2つ目要素(配列)が入ります。
(6) for col in row のcol に (5)で取り出したrow(配列)の1つ目の要素
(String: "A2")が入ります。
(7) 同じように最後まで続きます。
最初にfor row に 配列["A1", 〜 "H1"] が入るところに注意してください。
var myBoard = [
["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"],
["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"],
["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"],
["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"],
["A5", "B5", "C5", "D5", "E5", "F5", "G5", "H5"],
["A6", "B6", "C6", "D6", "E6", "F6", "G6", "H6"],
["A7", "B7", "C7", "D7", "E7", "F7", "G7", "H7"],
["A8", "B8", "C8", "D8", "E8", "F8", "G8", "H8"]
]
for row in myBoard {
for col in row {
print(col, terminator: " ")
}
print("")
}
// A1 B1 C1 D1 E1 F1 G1 H1
// A2 B2 C2 D2 E2 F2 G2 H2
// A3 B3 C3 D3 E3 F3 G3 H3
// A4 B4 C4 D4 E4 F4 G4 H4
// A5 B5 C5 D5 E5 F5 G5 H5
// A6 B6 C6 D6 E6 F6 G6 H6
// A7 B7 C7 D7 E7 F7 G7 H7
// A8 B8 C8 D8 E8 F8 G8 H8
条件に当てはまる要素だけ処理、条件に当てはまらない場合は無視してループの最初に戻る(continue コンティニュー)
ループ文の中でcontinue を読むと、ループの先頭に戻るという動きができます。
下の例では、
(1) let prefectures として都道府県の配列を持つ定数がある。
(2) var ken として文字列が入れられる空の配列をセットする。
(3) for pref で in prefectures の配列要素を一つづつ取り込む。
(4) pref.hasSuffix("県") で最後に県がつくかどうかを Bool型で返して false かど
うかをチェックする。
※hasSuffix()は配列の持つメソッドで、最後の文字(今回は最後の一文字)が
合致するかどうか、Bool型を返します。
(5) 上の(4)でfalseとなった場合("県"が最後の文字でない)continue が働く。
continueが働くと for pref に戻り、pref に次のprefectures要素が入り
ます。
上の(4)でtrue となった場合("県"が最後の文字である)if 文の内容が
スキップされるためcontinue は働かず、ken.append(pref) により
変数kenにそのprefが追加される。
let prefectures = ["北海道", "青森県", "栃木県", "埼玉県", "東京都", "静岡県", "滋賀県", "大阪府", "京都府"]
var ken = [String]()
for pref in prefectures {
if pref.hasSuffix("県") == false {
continue
}
ken.append(pref)
}
print(ken)
// ["青森県", "栃木県", "埼玉県", "静岡県", "滋賀県"]
上記をcontinue を使わずに書いてみます。
最初にtrueの場合に処理をして falseの場合は何もせずにループに戻ります。
こちらのほうがわかりやすいですね。
var ken = [String]()
for pref in prefectures {
if pref.hasSuffix("県") == true {
ken.append(pref)
}
}
print(ken)
// ["青森県", "栃木県", "埼玉県", "静岡県", "滋賀県"]
ある条件になったらループを抜け出す(break ブレーク)
ループ文の中でbreak を読むと、ループを抜け出して次の作業に移ります。
下の例では、
(1) var myLikeNumbers として空の配列を用意しておく。
(2) forループで変数 i が1から100,000までの繰り返し処理を開始する。
(3) 条件式として i.isMultiple(of: 3) && i.isMultiple(of: 7) を設定。
isMultiple(of: 数値) はIntの持つメソッドでその数値の倍数かどうかをBool型
で返す。(%を使った余りを使う方法でもできますね!)
この例では条件式を&&でつないでいる。&& で条件式をつなぐと、両方とも
trueを返す場合にだけ最終的にtrueを返す式となる。
今回の場合、3の倍数でありかつ7の倍数の場合にtrueを返す。
(4) 条件が適合すれば myLikeNumbers に加える。
(5) myLikeNumbers の要素数をカウントして10になっていれば、breakでループ処理を終了し、次の処理 print(myLikeNumbers) に移る。
var myLikeNumbers = [Int]()
for i in 1...100_000 {
if i.isMultiple(of: 3) && i.isMultiple(of: 7) {
myLikeNumbers.append(i)
if myLikeNumbers.count == 10 {
break
}
}
}
print(myLikeNumbers)
// [21, 42, 63, 84, 105, 126, 147, 168, 189, 210]
while 文
while文はwhileに続く条件文がtrueの間、処理を繰り返します。
上記のコードをwhileを使って書いて見ます。
下の例では、
(1) var myLikeNumbers として空の配列を置く。
(2) チェックする数値 i = 1として1から順に条件に適合するか調べていく。
(3) while文に続く条件式は、myLikeNumbers.count < 10 として
10個の答えが見つかるまでは続ける。
(4) 条件式として i.isMultiple(of: 3) && i.isMultiple(of: 7) を設定。
・条件に適合すればmyLikeNumbers に 数値 i を追加する。
(5) i に1を足して、while文に戻る。
(6) while文を開始する際にmyLikeNumbers.countが10以内か確認して
オーバーしていなければ継続、していれば中止する。
var myLikeNumbers = [Int]()
var i = 1
while myLikeNumbers.count < 10 {
if i.isMultiple(of: 3) && i.isMultiple(of: 7) {
myLikeNumbers.append(i)
}
i += 1
}
print(myLikeNumbers)
// [21, 42, 63, 84, 105, 126, 147, 168, 189, 210]
まとめ
配列
コレクション型はプログラミングで重要な役割を果たしますが、特に配列は基本となります。
調べてみるといろいろな発見もあると思いますので、少しづつ深掘りしてみてください。
条件分岐
条件文は、いろいろな書き方がありますが、書きやすさや読みやすさを考えて、使い分けをしていきたいですね。
ループ
ループ文はアルゴリズムの基本の一つです。
間違えても良いので、自分でいろいろと試してみると発見があって習熟も早くなると思います。
次回第6回内容 関数、Type(構造体、クラス、enum)です。
よろしくお願いします。
この記事が気に入ったらサポートをしてみませんか?