Swift Language
配列
サーチ…
前書き
構文
- Array <Element> //要素型の要素を持つ配列の型
- [Element] // Element型の要素を持つ配列型の構文糖
- [element0、element1、element2、... elementN] //配列リテラル
- [Element]() // [Element]型の新しい空の配列を作成します
- Array(count:repeatedValue :) //それぞれが
repeatedValue
初期化されたcount
要素の配列を作成します - Array(_ :) //任意のシーケンスから配列を作成します。
備考
配列は値の順序付けられたコレクションです。値は繰り返すことができますが、同じ型でなければなりません 。
価値セマンティクス
配列をコピーすると、元の配列内のすべての項目がコピーされます。
新しい配列を変更しても元の配列は変更されません 。
var originalArray = ["Swift", "is", "great!"]
var newArray = originalArray
newArray[2] = "awesome!"
//originalArray = ["Swift", "is", "great!"]
//newArray = ["Swift", "is", "awesome!"]
コピーされた配列は、変更されるまで元のメモリと同じ領域を共有します。この結果、コピーされた配列が最初に変更されたときにメモリ内に独自の領域が与えられると、パフォーマンスが低下します。
配列の基本
Array
は、Swift標準ライブラリの順序付きコレクション型です。 O(1)ランダムアクセスと動的再割り当てを提供します。 Arrayはジェネリック型なので、コンパイル時にその型の値がわかります。
Array
は値型であるため 、その可変性はvar
(可変)またはlet
(不変)として注釈を付けるかどうかによって定義されます。
型[Int]
(意味: Int
を含む配列)は、 Array<T>
構文的砂糖です。
The Swift Programming Languageの配列の詳細については、こちらをご覧ください。
空の配列
次の3つの宣言は同等です。
// A mutable array of Strings, initially empty.
var arrayOfStrings: [String] = [] // type annotation + array literal
var arrayOfStrings = [String]() // invoking the [String] initializer
var arrayOfStrings = Array<String>() // without syntactic sugar
配列リテラル
配列リテラルはカンマ区切りの要素を囲む角括弧で書かれています。
// Create an immutable array of type [Int] containing 2, 4, and 7
let arrayOfInts = [2, 4, 7]
コンパイラは通常、リテラルの要素に基づいて配列の型を推論できますが、明示的な型の注釈はデフォルトをオーバーライドできます。
let arrayOfUInt8s: [UInt8] = [2, 4, 7] // type annotation on the variable
let arrayOfUInt8s = [2, 4, 7] as [UInt8] // type annotation on the initializer expression
let arrayOfUInt8s = [2 as UInt8, 4, 7] // explicit for one element, inferred for the others
繰り返し値を持つ配列
// An immutable array of type [String], containing ["Example", "Example", "Example"]
let arrayOfStrings = Array(repeating: "Example",count: 3)
他のシーケンスからの配列の作成
let dictionary = ["foo" : 4, "bar" : 6]
// An immutable array of type [(String, Int)], containing [("bar", 6), ("foo", 4)]
let arrayOfKeyValuePairs = Array(dictionary)
多次元配列
スウィフトは、多次元配列をネスティングアレイによって作成され:の2次元アレイInt
ある[[Int]]
またはArray<Array<Int>>
)。
let array2x3 = [
[1, 2, 3],
[4, 5, 6]
]
// array2x3[0][1] is 2, and array2x3[1][2] is 6.
繰り返し値の多次元配列を作成するには、配列初期化子のネストされた呼び出しを使用します。
var array3x4x5 = Array(repeating: Array(repeating: Array(repeating: 0,count: 5),count: 4),count: 3)
配列値へのアクセス
次の例では、この配列を使用して値にアクセスする方法を示します
var exampleArray:[Int] = [1,2,3,4,5]
//exampleArray = [1, 2, 3, 4, 5]
既知のインデックスの値にアクセスするには、次の構文を使用します。
let exampleOne = exampleArray[2]
//exampleOne = 3
注意: インデックス2の値は、 Array
3番目の値です。 Array
は、 Array
最初の要素がインデックス0にあることを意味するゼロベースのインデックスを使用します 。
let value0 = exampleArray[0]
let value1 = exampleArray[1]
let value2 = exampleArray[2]
let value3 = exampleArray[3]
let value4 = exampleArray[4]
//value0 = 1
//value1 = 2
//value2 = 3
//value3 = 4
//value4 = 5
filterを使用してArray
サブセットにアクセスする:
var filteredArray = exampleArray.filter({ $0 < 4 })
//filteredArray = [1, 2, 3]
フィルタは、偶数だけのフィルタリングのような複雑な条件を持つことができます。
var evenArray = exampleArray.filter({ $0 % 2 == 0 })
//evenArray = [2, 4]
与えられた値のインデックスを返すことも可能で、値が見つからなければnil
返します。
exampleArray.indexOf(3) // Optional(2)
Array
内の最初、最後、最長、または最小値のメソッドがあります。 Array
が空の場合、これらのメソッドはnil
を返します。
exampleArray.first // Optional(1)
exampleArray.last // Optional(5)
exampleArray.maxElement() // Optional(5)
exampleArray.minElement() // Optional(1)
便利なメソッド
配列が空であるか、サイズを返すかを決定する
var exampleArray = [1,2,3,4,5]
exampleArray.isEmpty //false
exampleArray.count //5
配列の逆転注意:結果は、メソッドが呼び出された配列では実行されず、独自の変数に入れなければなりません。
exampleArray = exampleArray.reverse()
//exampleArray = [9, 8, 7, 6, 5, 3, 2]
配列内の値の変更
値を配列に追加するには複数の方法があります
var exampleArray = [1,2,3,4,5]
exampleArray.append(6)
//exampleArray = [1, 2, 3, 4, 5, 6]
var sixOnwards = [7,8,9,10]
exampleArray += sixOnwards
//exampleArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
配列から値を削除する
exampleArray.removeAtIndex(3)
//exampleArray = [1, 2, 3, 5, 6, 7, 8, 9, 10]
exampleArray.removeLast()
//exampleArray = [1, 2, 3, 5, 6, 7, 8, 9]
exampleArray.removeFirst()
//exampleArray = [2, 3, 5, 6, 7, 8, 9]
配列のソート
var array = [3, 2, 1]
新しいソートされた配列の作成
Array
はSequenceType
に準拠しているので、組み込みのソートメソッドを使用してソートされた要素の新しい配列を生成できます。
Swift 2では、これはsort()
メソッドで行います。
let sorted = array.sort() // [1, 2, 3]
スイフト3の時点で、 sorted()
。
let sorted = array.sorted() // [1, 2, 3]
既存の配列を所定の場所に並べ替える
Array
はMutableCollectionType
に準拠しているMutableCollectionType
、要素をMutableCollectionType
にソートできます。
Swift 2では、これはsortInPlace()
メソッドを使用して行われます。
array.sortInPlace() // [1, 2, 3]
Swift 3では、 sort()
名前に変更されました。
array.sort() // [1, 2, 3]
注:上記のメソッドを使用するには、要素が
Comparable
プロトコルに準拠している必要があります。
カスタムオーダーで配列をソートする
また、要素をComparable
必要がある配列に限定されない、ある要素を別の要素の前に配置するかどうかを定義するためにクロージャを使用して配列をソートすることもできます。たとえば、 Landmark
がComparable
であるとは意味がありませんが、高さや名前でランドマークの配列を並べ替えることはできます。
struct Landmark {
let name : String
let metersTall : Int
}
var landmarks = [Landmark(name: "Empire State Building", metersTall: 443),
Landmark(name: "Eifell Tower", metersTall: 300),
Landmark(name: "The Shard", metersTall: 310)]
// sort landmarks by height (ascending)
landmarks.sortInPlace {$0.metersTall < $1.metersTall}
print(landmarks) // [Landmark(name: "Eifell Tower", metersTall: 300), Landmark(name: "The Shard", metersTall: 310), Landmark(name: "Empire State Building", metersTall: 443)]
// create new array of landmarks sorted by name
let alphabeticalLandmarks = landmarks.sort {$0.name < $1.name}
print(alphabeticalLandmarks) // [Landmark(name: "Eifell Tower", metersTall: 300), Landmark(name: "Empire State Building", metersTall: 443), Landmark(name: "The Shard", metersTall: 310)]
// sort landmarks by height (ascending)
landmarks.sort {$0.metersTall < $1.metersTall}
// create new array of landmarks sorted by name
let alphabeticalLandmarks = landmarks.sorted {$0.name < $1.name}
注意:文字列が矛盾する場合、文字列の比較によって予期しない結果が生じる可能性があります。文字列の配列のソートを参照してください。
マップを使って配列の要素を変換する(_ :)
Array
はSequenceType
に準拠しているので、 map(_:)
を使用して、 A
の配列をB
型の配列に変換することができます。 (A) throws -> B
は型(A) throws -> B
クロージャを使用します。
例えば、これを使ってInt
の配列をString
の配列に変換することができます:
let numbers = [1, 2, 3, 4, 5]
let words = numbers.map { String($0) }
print(words) // ["1", "2", "3", "4", "5"]
map(_:)
は配列全体を反復し、与えられたクロージャを各要素に適用します。このクロージャの結果は、変換された要素で新しい配列を生成するために使用されます。
String
はInt
を受け取る初期化子を持っているので、この明確な構文を使うこともできます:
let words = numbers.map(String.init)
map(_:)
変換は配列の型を変更する必要はありません。たとえば、 Int
の配列に2を掛けることもできます:
let numbers = [1, 2, 3, 4, 5]
let numbersTimes2 = numbers.map {$0 * 2}
print(numbersTimes2) // [2, 4, 6, 8, 10]
flatMap(_ :)を持つ配列から特定の型の値を抽出する
things
アレイは、の値が含まれているAny
タイプを。
let things: [Any] = [1, "Hello", 2, true, false, "World", 3]
与えられた型の値を抽出し、その型の新しいArrayを作成することができます。すべてのInt(s)
を抽出し、安全な方法でInt
配列にInt
たいとしましょう。
let numbers = things.flatMap { $0 as? Int }
現在、 numbers
は[Int]
と定義されています。 flatMap
関数はすべてのnil
要素を破棄し、結果には次の値のみが含まれます。
[1, 2, 3]
配列のフィルタリング
SequenceType
に対してfilter(_:)
メソッドを使用すると、 クロージャーとして指定できる、指定された述部を満たすシーケンスの要素を含む新しい配列を作成できます。
たとえば、 [Int]
からの偶数のフィルタリング:
let numbers = [22, 41, 23, 30]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [22, 30]
[Person]
フィルタリングする[Person]
年齢が30歳未満の場合:
struct Person {
var age : Int
}
let people = [Person(age: 22), Person(age: 41), Person(age: 23), Person(age: 30)]
let peopleYoungerThan30 = people.filter { $0.age < 30 }
print(peopleYoungerThan30) // [Person(age: 22), Person(age: 23)]
flatMap(_ :)を使用して配列変換からnilをフィルタリングする
配列の要素に変換を適用して配列を作成するには、 map(_:)
と同様の方法でflatMap(_:)
使用できます。
extension SequenceType {
public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}
flatMap(_:)
このバージョンとの違いは、変換クロージャがオプションの値T?
を返すことを期待していることT?
各要素について次に、これらのオプション値をそれぞれ安全にアンラップし、 nil
フィルタリングして、 [T]
配列にします。
たとえば、 Int
のfailable String
初期化子を使用して[String]
を[Int]
に変換し、変換できない要素を除外するためにこれを行うことができます:
let strings = ["1", "foo", "3", "4", "bar", "6"]
let numbersThatCanBeConverted = strings.flatMap { Int($0) }
print(numbersThatCanBeConverted) // [1, 3, 4, 6]
flatMap(_:)
のオプションを使用して、 nil
をフィルタリングして、オプションの配列を非オプションの配列に単純に変換することもできます。
let optionalNumbers : [Int?] = [nil, 1, nil, 2, nil, 3]
let numbers = optionalNumbers.flatMap { $0 }
print(numbers) // [1, 2, 3]
レンジを持つ配列の添字付け
Rangeを使用して配列から一連の連続した要素を抽出することができます。
let words = ["Hey", "Hello", "Bonjour", "Welcome", "Hi", "Hola"]
let range = 2...4
let slice = words[range] // ["Bonjour", "Welcome", "Hi"]
Rangeで配列に添字をArraySlice
、 ArraySlice
が返されます。これは配列のサブシーケンスです。
この例では、Array of Stringsを持っているので、 ArraySlice<String>
返します。
ArraySliceはCollectionType
準拠しており、 sort
、 filter
などで使用できますが、その目的は長期保存用ではなく、一時的な計算用です。作業を終えるとすぐに配列に変換する必要があります。
このためには、 Array()
初期化子を使用します。
let result = Array(slice)
仲介ステップのない簡単な例をまとめると次のようになります。
let words = ["Hey", "Hello", "Bonjour", "Welcome", "Hi", "Hola"]
let selectedWords = Array(words[2...4]) // ["Bonjour", "Welcome", "Hi"]
配列値のグループ化
このような構造体があれば
struct Box {
let name: String
let thingsInside: Int
}
Box(es)
のアレイと、
let boxes = [
Box(name: "Box 0", thingsInside: 1),
Box(name: "Box 1", thingsInside: 2),
Box(name: "Box 2", thingsInside: 3),
Box(name: "Box 3", thingsInside: 1),
Box(name: "Box 4", thingsInside: 2),
Box(name: "Box 5", thingsInside: 3),
Box(name: "Box 6", thingsInside: 1)
]
私たちはthingsInside
プロパティでボックスをグループ化して、 key
が物の数で値がボックスの配列であるDictionary
を取得することができます。
let grouped = boxes.reduce([Int:[Box]]()) { (res, box) -> [Int:[Box]] in
var res = res
res[box.thingsInside] = (res[box.thingsInside] ?? []) + [box]
return res
}
今はグループ化された[Int:[Box]]
であり、以下の内容
[
2: [Box(name: "Box 1", thingsInside: 2), Box(name: "Box 4", thingsInside: 2)],
3: [Box(name: "Box 2", thingsInside: 3), Box(name: "Box 5", thingsInside: 3)],
1: [Box(name: "Box 0", thingsInside: 1), Box(name: "Box 3", thingsInside: 1), Box(name: "Box 6", thingsInside: 1)]
]
flatMapで配列変換の結果を平坦化する(_ :)
シーケンスの変換された要素からnil
を除外して配列を作成できるだけでなく、シーケンスS
を返すように変換クロージャがflatMap(_:)
バージョンもあります。
extension SequenceType {
public func flatMap<S : SequenceType>(transform: (Self.Generator.Element) throws -> S) rethrows -> [S.Generator.Element]
}
変換からの各シーケンスが連結され、各シーケンスの結合された要素 - [S.Generator.Element]
を含む配列が生成されます。
文字列の配列内の文字を結合する
たとえば、プライム文字列の配列を取得し、その文字を単一の配列に結合するために使用できます。
let primes = ["2", "3", "5", "7", "11", "13", "17", "19"]
let allCharacters = primes.flatMap { $0.characters }
// => "["2", "3", "5", "7", "1", "1", "1", "3", "1", "7", "1", "9"]"
上の例を打ち破る:
-
primes
は[String]
(配列はシーケンスなので、flatMap(_:)
を呼び出すことができます)。 - 変換クロージャは、
primes
の要素の1つString
(Array<String>.Generator.Element
)をArray<String>.Generator.Element
ます。 - クロージャは
String.CharacterView
型のシーケンスを返します。 - 結果は、各変換クロージャコール
[String.CharacterView.Generator.Element]
からのすべてのシーケンスの結合要素を含む配列になります。
多次元配列のフラット化
flatMap(_:)
は、変換クロージャー呼び出しから返されたシーケンスを連結するので、2D配列を1D配列に、3D配列を2D配列になど、多次元配列を平坦化するために使用できます。
これは、クロージャ内の指定された要素$0
(ネストされた配列)を返すことによって簡単に行うことができます:
// A 2D array of type [[Int]]
let array2D = [[1, 3], [4], [6, 8, 10], [11]]
// A 1D array of type [Int]
let flattenedArray = array2D.flatMap { $0 }
print(flattenedArray) // [1, 3, 4, 6, 8, 10, 11]
ストリングの配列のソート
最も簡単な方法はsorted()
を使うことです:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted()
print(sortedWords) // ["Ahola", "Bonjour", "Hello", "Salute"]
またはsort()
var mutableWords = ["Hello", "Bonjour", "Salute", "Ahola"]
mutableWords.sort()
print(mutableWords) // ["Ahola", "Bonjour", "Hello", "Salute"]
ソートの引数としてクロージャを渡すことができます:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted(isOrderedBefore: { $0 > $1 })
print(sortedWords) // ["Salute", "Hello", "Bonjour", "Ahola"]
後続のクロージャを使用する別の構文:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted() { $0 > $1 }
print(sortedWords) // ["Salute", "Hello", "Bonjour", "Ahola"]
しかし、配列内の要素が一貫していない場合、予期しない結果が発生します。
let words = ["Hello", "bonjour", "Salute", "ahola"]
let unexpected = words.sorted()
print(unexpected) // ["Hello", "Salute", "ahola", "bonjour"]
この問題に対処するには、小文字の要素をソートするか、
let words = ["Hello", "bonjour", "Salute", "ahola"]
let sortedWords = words.sorted { $0.lowercased() < $1.lowercased() }
print(sortedWords) // ["ahola", "bonjour", "Hello", "Salute"]
またはimport Foundation
をimport Foundation
、NSStringの比較メソッド( caseInsensitiveCompare
など)を使用します。
let words = ["Hello", "bonjour", "Salute", "ahola"]
let sortedWords = words.sorted { $0.caseInsensitiveCompare($1) == .orderedAscending }
print(sortedWords) // ["ahola", "bonjour", "Hello", "Salute"]
あるいは、発音区別符を管理できるlocalizedCaseInsensitiveCompare
使用します。
文字.numeric
に含まれる数値で文字.numeric
を適切にソートcompare
は、 .numeric
オプションとのcompare
を使用compare
ます。
let files = ["File-42.txt", "File-01.txt", "File-5.txt", "File-007.txt", "File-10.txt"]
let sortedFiles = files.sorted() { $0.compare($1, options: .numeric) == .orderedAscending }
print(sortedFiles) // ["File-01.txt", "File-5.txt", "File-007.txt", "File-10.txt", "File-42.txt"]
flatten()を使用した多次元配列の遅延フラット化
我々は多次元シーケンスの入れ子を遅延させるためにflatten()
を使うことができます。
たとえば、2D配列を1D配列にフラット化する:
// A 2D array of type [[Int]]
let array2D = [[1, 3], [4], [6, 8, 10], [11]]
// A FlattenBidirectionalCollection<[[Int]]>
let lazilyFlattenedArray = array2D.flatten()
print(lazilyFlattenedArray.contains(4)) // true
上記の例では、 flatten()
はFlattenBidirectionalCollection
を返しますFlattenBidirectionalCollection
は、配列の平坦化を遅延適用します。したがってcontains(_:)
は、 array2D
最初の2つのネストされた配列が平坦化されることのみを必要とします - 所望の要素を見つける際に短絡するからです。
配列の要素をreduce(_:combine :)で結合する
reduce(_:combine:)
は、シーケンスの要素を単一の値に結合するために使用できます。結果の初期値と、各要素に適用するクロージャーがあり、新しい累積値が返されます。
たとえば、数値の配列を合計するために使用できます。
let numbers = [2, 5, 7, 8, 10, 4]
let sum = numbers.reduce(0) {accumulator, element in
return accumulator + element
}
print(sum) // 36
0
を初期値に渡しています。これは、合計の論理初期値です。私たちがN
値を渡した場合、結果のsum
はN + 36
ます。 reduce
渡されるクロージャには2つの引数があります。 accumulator
は現在の累積値で、各反復でクロージャが返す値が割り当てられます。 element
は反復の現在の要素です。
この例のように、我々が通過している(Int, Int) -> Int
する閉鎖reduce
我々が実際に通過することができる-単に2つの入力の加算を出力している、 +
:オペレータがスイフトの関数であるように、直接オペレータの
let sum = numbers.reduce(0, combine: +)
インデックスを知らずに配列から要素を削除する
一般に、配列から要素を削除したい場合、 remove(at:)
関数を使用して簡単に削除できるように、その要素のインデックスを知る必要があります。
しかし、もし我々がインデックスを知らないが、削除されるべき要素の価値を知っていたらどうだろう!
したがって、配列の単純な拡張があります。この拡張は、配列の要素をインデックスなしで簡単に削除することを可能にします:
Swift3
extension Array where Element: Equatable {
mutating func remove(_ element: Element) {
_ = index(of: element).flatMap {
self.remove(at: $0)
}
}
}
例えば
var array = ["abc", "lmn", "pqr", "stu", "xyz"]
array.remove("lmn")
print("\(array)") //["abc", "pqr", "stu", "xyz"]
array.remove("nonexistent")
print("\(array)") //["abc", "pqr", "stu", "xyz"]
//if provided element value is not present, then it will do nothing!
また、間違って、次のようなことをした場合: array.remove(25)
つまり、別のデータ型で値を提供した場合、コンパイラはエラーを投げます。
cannot convert value to expected argument type
配列の最小要素または最大要素の検索
minElement()
およびmaxElement()
メソッドを使用すると、指定されたシーケンス内の最小または最大要素を見つけることができます。たとえば、数値の配列を使用すると、次のようになります。
let numbers = [2, 6, 1, 25, 13, 7, 9]
let minimumNumber = numbers.minElement() // Optional(1)
let maximumNumber = numbers.maxElement() // Optional(25)
これらのメソッドから返される値は、配列が空である可能性があるという事実を反映するためにオプションです。そうであれば、 nil
が返されます。
注:上記のメソッドでは、要素が
Comparable
プロトコルに準拠している必要があります。
カスタムオーダーで最小要素または最大要素を見つける
上記のメソッドをカスタムクロージャで使用して、ある要素を別の要素の前に配置する必要があるかどうかを定義することで、要素が必ずしもComparable
ない配列の最小要素または最大要素を見つけることができます。
たとえば、ベクトル配列を使用すると、次のようになります。
struct Vector2 {
let dx : Double
let dy : Double
var magnitude : Double {return sqrt(dx*dx+dy*dy)}
}
let vectors = [Vector2(dx: 3, dy: 2), Vector2(dx: 1, dy: 1), Vector2(dx: 2, dy: 2)]
// Vector2(dx: 1.0, dy: 1.0)
let lowestMagnitudeVec2 = vectors.minElement { $0.magnitude < $1.magnitude }
// Vector2(dx: 3.0, dy: 2.0)
let highestMagnitudeVec2 = vectors.maxElement { $0.magnitude < $1.magnitude }
let lowestMagnitudeVec2 = vectors.min { $0.magnitude < $1.magnitude }
let highestMagnitudeVec2 = vectors.max { $0.magnitude < $1.magnitude }
インデックスへの安全なアクセス
配列インデックスに次の拡張を追加すると、インデックスが境界内にあるかどうかを知らなくてもアクセスできます。
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
例:
if let thirdValue = array[safe: 2] {
print(thirdValue)
}
2つの配列とzipの比較
zip
関数は、 SequenceType
型の2つのパラメータをZip2Sequence
、各要素に第1のシーケンスの値と第2のシーケンスの値を含むZip2Sequence
を返します。
例
let nums = [1, 2, 3]
let animals = ["Dog", "Cat", "Tiger"]
let numsAndAnimals = zip(nums, animals)
nomsAndAnimalsに次の値が含まれるようになりました
シーケンス1 | シーケンス1 |
---|---|
1 | "Dog" |
2 | "Cat" |
3 | "Tiger" |
これは、各配列のn番目の要素の間で何らかの種類の比較を実行する場合に便利です。
例
与えられたInt(s)
2つの配列
let list0 = [0, 2, 4]
let list1 = [0, 4, 8]
list1
各値がlist0
関連する値のlist1
かどうかを確認する必要があります。
let list1HasDoubleOfList0 = !zip(list0, list1).filter { $0 != (2 * $1)}.isEmpty