Quantcast
Channel: 配列タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 834

Swiftにおける配列操作まとめ

$
0
0

目次

はじめに
部分置換
部分配列の型
配列のプロパティ
配列のメソッド
シーケンス操作
最後に

はじめに

配列操作のまとめです。主に、部分配列、配列のプロパティ、メソッド、シーケンス操作についてまとめています。
SequenceとCollectionや基本的な配列のアクセス方法、その他配列以外の知識が必要なものは今回は説明していません。

部分置換

vara=["赤","青","緑","白","黒"]//①a[1...1]=["橙","茶","紫"]print(a)// ["赤", "橙", "茶", "紫", "緑", "白", "黒"]//②a[2...3]=["黄"]print(a)// ["赤", "橙", "黄", "緑", "白", "黒"]//③a[1...2]=[]print(a)// ["赤", "緑", "白", "黒"]//④a[2...]=["銀"]print(a)// ["赤", "緑", "銀"]//⑤a[...]=["金"]print(a)// ["金"]

注意
番号ごとに毎回配列の要素が変わっていることに注意してください。(前番号のコメントを参照)
"青""橙", "茶", "紫"に変更しています。ただし、a[1]ではだめです。
② index番号が2から3である"茶""紫""黄"に変更しています。
③ index番号が1から2である"橙""黄"を消去しています。
④ index番号が2から最後の要素までの"白""黒""銀"に変更しています。
...で配列の全要素を指定し、"金"に変更しています。

部分配列の型

letb=["北","東","南","西"]letc=b[2...]print(type(of:c))// ArraySlice<String>

部分配列とは配列の添字に範囲を指定したものです。(a[4...5], a[2...], a[...1], a[...]など)
これらの型はArray型ではなく、ArraySlice型になります。
ArraySlice型は必ずしも0からインデックス番号が振られるわけではありません。

print(c.startIndex)// 2print(c[2])// 南print(c[3])// 西

このように、ArraySlice型は必ずしも0からインデックス番号が始まるとは限りません。
また、以下のようにすることでArraySlice型を0からインデックス番号が始まるArray型にすることができます。

letd=[String](c)print(d)// ["南", "西"]print(d.startIndex)// 0

配列のプロパティ

概要宣言説明
要素数count要素数を整数値で返す
先頭要素first最初の要素を返す(なければnilを返す)
末尾要素last最後の要素を返す(なければnilを返す)
空配列かisEmpty空配列であればtrue,要素があればfalseを返す
lete=[Character]("ABCDEFGHIJKLMNOPQRSTUVWXYZ")print(e)// "A"から"Z"までの一文字ずつの配列print(e.count)// 26print(e.first!)// Aprint(e.last!)// Zprint(e.isEmpty)// false

配列のメソッド

概要宣言説明
検索firstIndex引数の値が最初に現れる位置の添字を返す(なければnilを返す)
検索lastIndex引数の値が最後に現れる位置の添字を返す(なければnilを返す)
部分列prefix指定した個数分の先頭部分の部分配列を返す
部分列suffix指定した個数分の末尾部分の部分配列を返す
部分列dropFirst指定した個数分の先頭要素を取り除いた残りを部分配列として返す
部分列dropLast指定した個数分の末尾要素を取り除いた残りを部分配列として返す
追加append配列の末尾に値を付け加える
挿入insert指定した位置に値を挿入する
削除remove指定した位置の要素を削除する
削除removeFirst最初の要素を消去する
削除removeLast最後の要素を消去する
削除removeAll要素を全て消去し、配列の要素数を0にする
整列sort要素を昇順に並べ替える
整列sorted要素を昇順に並べ替えて新しい配列を返す
ランダムrandomElement要素をランダムに選んで一つ返す
シャッフルshuffle要素をランダムに並び替える
シャッフルshuffled要素をランダムに並び替えた配列を返す
逆順reverse要素を元の配列と逆にする
逆順reversed要素を元の配列と逆にした配列を返す
varf=["A","B","B","C","C","D","E"]print(f.firstIndex(of:"B")!)// 1print(f.lastIndex(of:"C")!)// 4print(f.prefix(3))// ["A", "B", "B"]print(f.suffix(5))// ["B", "C", "C", "D", "E"]print(f.dropFirst())// ["B", "B", "C", "C", "D", "E"]print(f.dropFirst(3))// ["C", "C", "D", "E"]print(f.dropLast())// ["A", "B", "B", "C", "C", "D"]print(f.dropLast(5))// ["A", "B"]f.append("G")// f -> ["A", "B", "B", "C", "C", "D", "E", "G"]f.insert("H",at:3)// -> ["A", "B", "B", "H", "C", "C", "D", "E", "G"]f.remove(at:5)// f -> ["A", "B", "B", "H", "C", "D", "E", "G"]f.removeFirst()// f -> ["B", "B", "H", "C", "D", "E", "G"]f.removeLast()// f -> ["B", "B", "H", "C", "D", "E"]f.removeFirst(2)// f -> ["H", "C", "D", "E"]f.removeLast(2)// f -> ["H", "C"]f.removeAll()// f -> []varg=[2,4,1,6,5,3]g.sort()// g -> [1, 2, 3, 4, 5, 6]varh=["a","c","b","e","d"]leti=h.sorted()print(h)// ["a", "c", "b", "e", "d"]print(i)// ["a", "b", "c", "d", "e"]var宝くじ=["100円","300円","1000円","1万円","100万円","ハズレ"]print(宝くじ.randomElement()!)// たとえば"ハズレ"varj=[2,4,1,6,5,3]j.shuffle()// j -> たとえば[2, 5, 3, 1, 6, 4]vark=["a","e","c","d","b"]letl=k.shuffled()print(k)// ["a", "e", "c", "d", "b"]print(l)// ["d", "a", "e", "c", "b"]varm=["S","w","i","f","t"]m.reverse()// ["t", "f", "i", "w", "S"]print(m)letn=[1,2,3]leto=n.reversed()print(o)// ReversedCollection<Array<Int>>(_base: [1, 2, 3]) え?

注意するべきことのみ解説します。
prefix, suffix, dropFirst, dropLastはArraySlice型が返されます。
FirstやLastのついたメソッドに引数を指定するとたとえばLastであれば、最後から引数で指定したインデックス番号までを操作の対象とします。
sort()sorted()の違いはsort()が配列そのものを変更するのに対し、sorted()は配列そのものは変更を加えず、新しく配列を作り、返します。shuffle()shuffled()の違いも同様です。
reversed()は、、、見なかったことにしたい。。。reversed()は実際に要素が逆順になったArrayを生成せず、そのようにふるまうReversedCollectionという型のインスタンスを返します。
参考記事を貼っておきます(reversed()の参考記事)

シーケンス操作

filter

条件を満たすものだけを取り出し、新しい配列を作ることができる。
たとえば、100までの正の整数で13または43の倍数であるものを含む配列を作ってみます。

letp=[Int](1...100)letq=p.filter{$0%13==0||$0%43==0}print(q)// [13, 26, 39, 43, 52, 65, 78, 86, 91]

クロージャの詳しい解説はしませんが、$0に1から100まで順番に入っていきます。初めは1が入り、{}のなかの条件式$0 % 13 == 0 || $0 % 43 == 0はfalseになるので、1は作成される配列の中に入りません。次に2が入り、、、というふうに一つ一つの要素が条件を満たすか確認していき、条件を満たす(trueを返す)要素のみの配列を新しく作成し、定数qに格納しています。

map

配列の各要素に指定した処理を適応させ、その結果からなる新しい配列を作成することができる。
たとえば、次のように配列rの全ての要素を2倍した配列を新たに作りたいとします。

letr=[10,20,30,40]lets=r.map{$0*2}print(s)// [20, 40, 60, 80]

$0に10から40まで順番に入っていき、条件式$0 * 2で全ての配列の要素を2倍しています。その配列を定数sに格納しています。
たとえば、次のようにfilterを合わせて使うこともできます。

lett=["佐々木","田中","山本","大和田"]letu=t.map{$0+"さん"}.filter{$0.count>=5}print(u)// ["佐々木さん", "大和田さん"]

まず、mapで配列tの各要素に"さん"をつけています。mapによって新たに作られた配列に、さらにfilterで文字数が5以上になった場合の配列を新たに作っています。その新たに作られた配列を定数uに格納しています。

mapValues

mapの返り値は辞書も集合も要素が格納された配列です。ただし、辞書については、含まれる要素の値に対して処理を適応し、その結果としてキーを組み合わせて新しい辞書を返すメソッドが用意されています。

letsteps=[90,80,70,60]letevals=["秀","優","良","可","不可"]letv=["太郎":68,"二郎":50,"三郎":62,"四郎":90]letmarks=v.mapValues{(point:Int)->Stringinvarindex=0forstepinsteps{ifpoint>=step{break}index+=1}returnevals[index]}print(marks)//たとえば["二郎": "不可", "四郎": "秀", "太郎": "可", "三郎": "可"]

ただし、辞書は配列のように順番通りに出力されないことに注意してください。今回の場合、vが辞書で、mapValuesしたものを定数marksに格納しているので、print(marks)すると順番が変わることがあります。

compactMap

mapやmapValueはどちらも処理前と処理後の一対一に対応しています。しかし、目的によってはfilterのように不要な要素を取り除きたいということもあります。そのような時に用いられるシーケンスのメソッドがcompactMapです。

letpeople=[["Name":"れおん","Pet":"ハリネズミ","BloodType":"O"],["Name":"承太郎","BloodType":"B"],["Name":"花京院","身長":"178cm"],["Name":"ポルナレフ","Pet":"イギー","BloodType":"AB"]]letpets=people.compactMap{$0["Pet"]}print(pets)// ["ハリネズミ", "イギー"]

承太郎と花京院は"Pet"を持っていないのでcompactMapの条件式$0["Pet"]がnilになり、ハリネズミとイギーが入った配列が新たに作られています。

flatMap

flatMapはすべての要素をシーケンスへと変換し、さらに、 それを1つのシーケンスに連結します。

letbookLists=["Aさん":["本1","本2"],"Bさん":[],"Cさん":["本3"]]letbooks=bookLists.flatMap{$0.value}print(books)// たとえば["本3", "本1", "本2"]

reduce

シーケンスに含まれる要素を一つずつ全て使って処理を行い、その結果として一つの値を返します。
たとえば、数値の列の合計を求めるには次のようにします。

letw=[1,2,5,1,8,2,3]letsum=w.reduce(0){$0+$1}print(sum)// 22

一周目は$0に第一引数にある初期値0が入り、$1には配列の初めの要素1が入ります。よって、0 + 11が得られる。
二周目は$0に先ほど一周目で得られた1が入り、$1には配列の二番目の要素2が入ります。よって、1 + 23が得られる。
三周目は$0に先ほど二周目で得られた3が入り、$1には配列の三番目の要素5が入ります。よって、3 + 58が得られる。
これを繰り返していくと、配列wの合計値が求められる。

forEach

配列の各要素に順番に適用していく。
for-in文と基本的には同じだが、forEachはbreakなどが使えない。

letnumberWords=["one","two","three"]numberWords.forEach{print($0)}//"one"//"two"//"three"

enumerated

シーケンスから取り出した順の通し番号と要素からなるタプルを含むシーケンスを返す。

letnames=["名前A","名前B","名前C"]fortinnames.enumerated(){print(t)}//(offset: 0, element: "名前A")//(offset: 1, element: "名前B")//(offset: 2, element: "名前C")

タプルのラベルは無視しても良い。

zip

二つのシーケンスを引数としてそれぞれの要素をタプルとする新しいシーケンスを返します。

fortinzip("アイウエオ",[1,2,3]){print(t)}//("ア", 1)//("イ", 2)//("ウ", 3)

repeatElement

引数で指定したインスタンスを指定した個数だけ含むシーケンスを作成して返します。

fortinzip(["佐々木","田中","佐藤"],repeatElement("Hello",count:2)){print(t)}//("佐々木", "Hello")//("田中", "Hello")

sequence

最初から全ての要素が決まっているのではなく、必要が生じてから次の要素を計算して返すという、遅延評価によるシーケンスのインスタンス生成して返します。

varseq=sequence(first:10000000,next:{$0/10})forpinseq.prefix(10){print(p)}//10000000//1000000//100000//10000//1000//100//10//1//0//0

lazy

遅延評価を行うとシーケンスの全要素を処理する必要がなくなったり、最初の結果をすばやく得たりできる場合があります。
lazyを利用して実行順序が変化する例を示します。

funcf(_n:Int)->Bool{print(n,terminator:" ")returnn&1==0}(0...5).filter(f).forEach{print("[\($0)]",terminator:" ")// 0 1 2 3 4 5 [0] [2] [4]}(0...5).lazy.filter(f).forEach{print("[\($0)]",terminator:" ")// 0 [0] 1 2 [2] 3 4 [4] 5 }

最後に

初めての投稿ですが、なんとか書き終えれてよかったです。
Swift難しい。。。


Viewing all articles
Browse latest Browse all 834

Trending Articles