[Swift] コレクション(Array)の使い方

Swiftの配列コレクションを使ってみた
Arrayって言う位だからList構造ではなくてホントに配列なのかも?

宣言のサンプル

// 空配列の宣言
var citylist = [String]()

// 宣言時に要素を設定
// ※型宣言は省略可能
// String[]  は Array<String>のシンタックスシュガー
let ishikawaCitylist:[String] = ["kanazawa","komatsu","nanao","kaga"]

構文が簡単でいいね!
 

要素の追加とか削除とか

// 要素が設定されているか判定
if citylist.isEmpty {
    NSLog("からっぽ")
}

// 要素を追加
// +=でも追加できるし (array も 要素も直接足せる)
citylist += ishikawaCitylist
citylist += "nonoichi"

// appendでも追加可能
citylist.append("suzu")

// 要素を挿入
citylist.insert("wakura",atIndex:0)


// 要素を削除
// この時取り除かれた要素が返却される
let kanazawa = citylist.removeAtIndex(1)
let suzu = citylist.removeLast()
NSLog("is kanazawa?:%@", kanazawa)
NSLog("is suzu?:%@", suzu)

arrayをループさせるときはこんな感じで


// for-each (for-in) なループ
for city in citylist {
    NSLog("cities A:%@", city)
}
// 同時にindexを求める場合
for (index,city) in enumerate(citylist){
    NSLog("cities B:%@ (%d)", city,index)
}

// よくあるループカウンタを使ったforループ
for var i = 0; i < citylist.count; i++ {
    NSLog("cities C:%@ (%d)", citylist[i],i)
}

 

もちろん多次元配列も作れます

// 2次元配列
let matrix:Int[][] = [[1,2,3,4,5,6,7] ,[11,12,13,14,15,16,17]]
let matrix:[[Int]] = [[1,2,3,4,5,6,7] ,[11,12,13,14,15,16,17]]
// matrix[0] は [1,2,3,4,5,6,7]
// matrix[0][1] は 2
NSLog("matrix[0]:%@", matrix[0])
NSLog("matrix[0][1]:%d", matrix[0][1])

(XCode6.0-beta3でArrayの動作が大きく変更となりました)

でこれは要注意なんだけど、arrayってのは構造体(値型)って事もあり参照のコピーには
いろいろ癖がある。


// arrayの参照をコピーする場合は要注意!
// 例えばこのように単純に代入して複写すると同じものとして扱われる
var copiedList = citylist
copiedList[0] = "yokohama"
NSLog("simple assign  citylist[0]:\(citylist[0])  copiedList[0]:\(copiedList[0])")
// ・・・ citylist[0]:yokohama  copiedList[0]:yokohama

// だけど一方にappendなどで要素の数を変更した場合には別の配列として扱われる!!
// なのでこの例では citylist と copiedList で違う値が取得される
copiedList.append("kumamoto")
copiedList[0] = "nagasaki"
NSLog("after append  citylist[0]:\(citylist[0])  copiedList[0]:\(copiedList[0])")
// ・・・  citylist[0]:yokohama  copiedList[0]:nagasaki
// これはハマり所でバグ臭がプンプンするぜ〜

// 常に別物として使う場合はunshareってのを呼べば良い
var copiedListB = citylist
copiedListB.unshare()
copiedListB[0] = "fukuoka"
NSLog("unshare  citylist[0]:\(citylist[0])  copiedListB[0]:\(copiedList[0])")
// ・・・  citylist[0]:yokohama  copiedListB[0]:nagasaki

// もしくはcopyでシャローコピーする
var copiedListC = citylist.copy()

// letだとappend出来ないのでarrayはletで宣言するのがバグの要因を減らす事になるかな?


// 関数に渡した場合の挙動
var list1 = [1,2,3]

// 関数内で要素の値を変更した場合の挙動
// 関数内からの操作でも呼び出し元のArrayが変更されている
func modifyArrayA(arr:Array<Int>) {
    arr[0] = 999
}
modifyArrayA(list1)
NSLog("modifyArrayA  list1[0]:\(list1[0])")
//・・・ list1[0]:999

// letを付けても同様
func modifyArrayB(let arr:Array<Int>) {
    arr[0] = 999
}
list1[0] = 1
modifyArrayB(list1)
NSLog("modifyArrayB  list1[0]:\(list1[0])")
//・・・ list1[0]:999



// 関数内で要素数を修正した場合
// 同一関数内での操作と同様にappendした時点で別ものとして扱われているようだ
func modifyArrayC(var arr:Array<Int>) {
    arr.append(4)
    arr[0] = 999
}
list1[0] = 1
modifyArrayC(list1)
NSLog("modifyArrayC  list1[0]:\(list1[0]) count:\(list1.count)")
//・・・ list1[0]:1 count:3

// inoutを指定した場合には要素数を変更を含む操作が呼び出し元の変数に反映される
func modifyArrayD(inout arr:Array<Int>) {
    arr.append(4)
    arr[0] = 999
}
list1[0] = 1
modifyArrayD(&list1)
NSLog("modifyArrayD  list1[0]:\(list1[0]) count:\(list1.count)")
// list1[0]:999 count:4


うーん、引数の配列へ影響を与えるかどうか明示的にしたいんだけど、どうすればいいかな?
ちゃんと方針を決めておかないと絶対バグの温床になるよ。これ。

  
(XCode6.0-Beta3での変更)
→ beta3では随分スッキリしました

letで宣言したArrayは変更不可

let immutableArray = ["りんご","オレンジ","キューイ"]
// これはエラーとなる   (beta2まではOK)
// immutableArray[0] = "すいか"
// もちろんこれもエラー 
// immutableArray.append("すいか")

varで宣言すればもちろん変更可能

var mutableArray = ["大根","人参"]
mutableArray[0] = "こぼう"
mutableArray.append("きゃべつ") 

問題(?)だった別変数へのコピーは、値型らしく完全に別ものとして扱われます
※unshareは無くなったようです

var mutableArray = ["ごぼう","人参","ぎゃべつ"]

var mutableArray2 = mutableArray
mutableArray2[0] = "レタス"
for item in mutableArray {
    NSLog("mutableArray:%@", item)
}
//  ごぼう 人参 きゃべつ

for item in mutableArray2 {
    NSLog("mutableArray2:%@", item)
}
//  レタス 人参 きゃべつ

inoutな変数の場合は今まで通り元のArrayを変更してくれます


func modifyArrayInout(inout arr:[String]) {
    arr.append("きゅうり")
    arr[0] = "なすび"
}

var mutableArray = ["ごぼう","人参","ぎゃべつ"]
modifyArrayInout(&mutableArray);
for item in mutableArray {
    NSLog("mutableArray:%@", item)
}
// なすび 人参 きゃべつ きゅうり

 
 
 
 
NSArrayをSwiftの配列にキャストする時は下記のように行う

// NSArrayをString[]にキャスト
let wrestlers: NSArray = ["鶴田", "渕", "田上"]
if let wrestlersArr = wrestlers as? String[] {
    for  wrestlerName in wrestlersArr {
        NSLog("\(wrestlerName)")
    }
}

 

最後にArrayを使うときに便利そうなmapってメソッドのサンプル
arrayの各要素を変換して別のarrayとして返します
scalaのseq.mapとほぼ同じ機能ですね
この例ではArray<Int>からArray<String>に変換しています

var list1 = [1,2,3]
let stringlist:Array<String> = list1.map {
    num -> String in
    return String(num)
}
NSLog("string list %@",stringlist)

 
 
 

(2014-07-11) XCode6.0-beta3での仕様変更を反映

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です