配列に後から要素を追加したり削除したりする練習です。
7行目までの部分でcharactersという配列が用意され、Blu型キャラクター、ワープポータル、Hopper型キャラクター、宝石が入れられます。キャラクター以外のものが混じってたりするので修正したいのですが、直接4行目や6行目を削除することはできません。ここでは一旦作って中身を入れてしまった後の配列に対し、.removeメソッドで要素を消したり.insertメソッドで追加したりする練習をするのが目的だからです。
まず正解例はこんな感じになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//最初に用意されるcharacters配列 (余分なものが含まれていますがここは編集できません) characters = [ Character(name: .blu), Portal(color: #colorLiteral(red: 0.91, green: 0.47, blue: 0.64, alpha: 1)), //ピンク Character(name: .hopper), Gem() ] // Remove the portal. (ポータルを削除しなさい) characters.remove(at: 1) // Remove the gem. (宝石を削除しなさい) characters.remove(at: 3) //配列の範囲外エラーになる // Insert the expert. (expertを追加しなさい) characters.insert(Expert(), at: 1) var rowPlacement = 0 //毎回位置をズラすための変数 //characters配列の中の1つ1つをcharcter変数にセットして繰り返す for character in characters { world.place(character, at: Coordinate(column: 1, row: rowPlacement)) rowPlacement += 1 //row:パラメーターを1ずつズラす為、1を足していく } |
■配列から要素を削除したり追加するには
配列名に対してドット記法で.removeや.insertメソッドを指定します。この際、.removeなら何番目の要素を削除するかをパラメーターとして指定してやります。
1 |
(配列名).remove(at: (何番目の要素を削除するか)) |
ここで非常に重要な注意点があります。3〜6行目をみると、余分な要素であるポータルと宝石は2番目と4番目にあります。配列の中身は0から数えるルールなので、
1 2 |
characters.remove(at: 1) //ポータルを削除 characters.remove(at: 3) //宝石を削除 |
としてみたのではないでしょうか?そうすると宝石を削除する方が配列の範囲外エラーになります。どうしてでしょう?この理由をイメージできる感覚はプログラミングにとても重要な気がしますので、じっくり考えてみてください。正解は最後に。
でとりあえず次は挿入。.insertの場合は、なにを足すかと、どこに割り込ませるかを指定します。
1 |
(配列名).insert((追加するオブジェクト), at: (何番目に割り込ませるか)) |
■16行目以降について
今回はループ毎に配列の中身を順に読み出しても変化するのはキャラクターの種類だけです(Blu->Expert->Hopper)。それとは別に配置する位置は自分でズラしていかなければなりません。そこで、rowの値が繰り返し毎に1ずつズレていくよう別の変数rowPlacementを用意して工夫します。最初に16行目で0をセットしておくことで、初回のループではrow:パラメーターが0になり、(1,0)の位置にBluが出現します。そして繰り返しで戻る前の20行目で1を足しておくことで、2回目は(1,1)にExpertが、3回目は(1,2)にHopperが出てくるわけです。
■なぜ12行目は範囲外エラーになるのか?
さて、あえて正解例コードにバグを入れておいた「範囲外エラー」の答え合わせについてです。範囲外エラーなので試しに数字を小さくしてみれば上手くいっちゃったりするかも知れません。そう、正解は、3ではなく2ですね。大事なのは何故かです。これは直前の行でワープポータルを削除したことに関係します。
最初はこうでした。
1 2 3 4 5 6 |
characters = [ Character(name: .blu), Portal(color: #colorLiteral(red: 0.91, green: 0.47, blue: 0.64, alpha: 1)), //ピンク Character(name: .hopper), Gem() ] |
その後で、
1 |
characters.remove(at: 1) |
したらどうなるでしょう?
1 2 3 4 5 |
characters = [ Character(name: .blu), Character(name: .hopper), Gem() ] |
こうですね。つまり、charactersの中のオブジェクト数は4から3に減りました。そして、Gem()の順番も4番目でなく3番目に繰り上げになっています。配列は0番スタートなので、3番目ということは0,1,2で2を指定する必要があるわけです。3を指定するということは存在しない4番目を削除しようとすることになるので、範囲外エラーというわけですね。
もちろん、.insertする場合も影響しますので、常にその時点で配列の中がどうなっているかを意識しましょう。