🗂

【翻訳】7 Array Features That Every Swift Developer Should Know

2023/07/26に公開

Array 、 Set 、 Dictionary を含む Swift Collection は誰もが知っているはずです。これら3つの型は、 iOS の開発において、データをコレクション形式で保存するのにとても便利です。

この記事では、Array で使用できる便利なメソッドについて説明します。 Array は同じ型のデータを順番に並べたリストに格納し、その要素には0から始まるインデックスでアクセスできます。さまざまなデータ型( Int、 String 、 Double 、 Any 、 Optional など)や、ユーザー定義の Class や Structを格納することができます。

基本構文

各メソッドを見ていく前に、配列の基本構文を少し復習しておきましょう。以下のコードとコメントの説明を参照します。

// Mutable Array (use let to prevent changes)
// Empty array with type Int
var score: [Int] = []
// Empty array with type String
var names = [String]()
// Array with Int data
var numbers = [99, 4, 80, 12, 33, 0]
// Get number at index 4
let scoreStudent4 = numbers[3];
// Add new item at last index
numbers.append(100)
// Append array into it
numbers.append(contentsOf: [30, 44, 21])
// Output: [99, 4, 80, 12, 33, 0, 100, 30, 44, 21]
print(numbers)
// remove all items
numbers.removeAll()

以下は、オブジェクトを含む配列を示すコードです。これから説明する 全ての機能で、このサンプルデータを使用します。

struct Student {
    let name: String
    let score: Int
    let gender: Gender
    let location: String?
}
// Array of objects
var students = [
    Student(name: "John", score: 79, gender: .male, location: nil),
    Student(name: "Bob", score: 44, gender: .male, location: nil),
    Student(name: "Alice", score: 0, gender: .female, location: "New York"),
    Student(name: "Rose", score: 88, gender: .female, location: "San Francisco"),
    Student(name: "Kurt", score: 90, gender: .male, location: nil),
    Student(name: "Fatima", score: 83, gender: .female, location: "LA"),
    Student(name: "Julie", score: 56, gender: .female, location: "Miami"),
    Student(name: "Patrick", score: 61, gender: .male, location: nil),
    Student(name: "Spongebob", score: 16, gender: .male, location: "Boston")
]

1. 最初と最後の項目の取得

この first() と last() がない場合、通常は インデックス0 と N-1 を使用して最初と最後の要素にアクセスします。

let firstStudent = students.first
let lastStudent = students.last
print(firstStudent?.name)
print(lastStudent?.name)
// Output: Optional("John")
// Output: Optional("Spongebob")

条件付き

これは簡単です。しかし、「50点未満」を持つ配列から最初のものを取得したい場合はどうすればいいでしょうか。そう、まだ first() メソッド を使っていますが、今回は特定の条件を含む where クロージャ を使っています。同じクロージャ条件を last() メソッド にも適用できます。

// Example 1
let firstStudent = students.first(where: { $0.score < 50 })
print(firstStudent?.name)
// Output: Optional("Bob")
let lastStudent = students.last(where: { $0.score > 100 })
print(lastStudent?.name)
// Output: nil
// nil because cannot find in array with specified condition
// Example 2 - Without shorthand argument
let firstStudent = students.first { student in
    return student.score > 50
}

上のコードを見ると、 $0 はインライン・クロージャーに渡される最初の省略記法引数です。この場合、渡される引数は "Student" オブジェクトです。次のセクションでは、 $0 と $1 を使ったインラインクロージャを使い続けます。

省略記法の引数については、 Swift のドキュメントでよく説明されています。
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/

Swift は自動的にインラインクロージャに省略記法の引数名を提供し、 $0 、 $1 、 $2 などの名前でクロージャの引数の値を参照するのに使うことができます。

2. map を使った配列の変換

このセクションでは、 map() メソッド を使用します。以下は、生徒から map された3種類の配列( Int の配列、 String の配列、 User の配列)です。

import Foundation
// Array of scores [Int]
let scores = students.map { $0.score }
print(scores)
// Output: [79, 44, 0, 88, 90, 83, 56, 61, 16]
// [String]
let sentences = students.map { student in
    return "\(student.name) score is \(student.score)"
}
print(sentences)
// Output: ["John score is 79", "Bob score is 44", "Alice score is 0", "Rose score is 88", "Kurt score is 90", "Fatima score is 83", "Julie score is 56", "Patrick score is 61", "Spongebob score is 16"]
// Array of Users [User]
struct User {
    let id = UUID()
    let name: String
}

let users = students.map { User(name: $0.name) }

3. CompactMap

これは map メソッド と似ていますが、非オプションの項目を含む結果を取得したい場合に使用します。以下の例では、生徒の位置のリストを取得します。 map() と compactMap() の出力の違いを見てください。

// Map
let studentLocation1 = students.map({ $0.location })
print(studentLocation1)
// Output: [nil, nil, Optional("New York"), Optional("San Fancisco"), nil, Optional("LA"), Optional("Miami"), nil, Optional("Boston")]

// CompactMap
let studentLocation2 = students.compactMap({ $0.location })
print(studentLocation2)
// Output: ["New York", "San Francisco", "LA", "Miami", "Boston"]

4. 条件付きソート

この例では、学生の配列は最初にスコアでソートされ、次に String (ソートされた学生の名前) の配列にマップされます。

// sort student by score
let sortedArray = students.sorted(by: { $0.score > $1.score })
// map result into list of names
print(sortedArray.map { $0.name })
// Output: ["Kurt", "Rose", "Fatima", "John", "Patrick", "Julie", "Bob", "Spongebob", "Alice"]

5. フィルタリング

filter() メソッド は、クロージャの内部で与えられた条件に基づいてマッチする要素を見つけるために使用されます。50点以上の学生のリストを取得してみましょう。次に、男子学生のリストを取得します。

// filter students score above 50
let goodStudents = students.filter({ $0.score > 50 })
// again we only print the names
print(goodStudents.map { $0.name })
// Output: ["John", "Rose", "Kurt", "Fatima", "Julie", "Patrick"]
// get male students
let maleStudents = students.filter({ $0.gender == .male })
print(maleStudents.map { $0.name })
// Output: ["John", "Bob", "Kurt", "Patrick", "Spongebob"]
// multiple condition
let goodMaleStudents = students.filter({ $0.score > 50 && $0.gender == .male })
// Output: ["John", "Kurt", "Patrick"]

6. 最高値と最低値の取得

最高値または最低値を取得する一般的な方法は、first() または last() で sort() メソッドを使用することです。しかし、Swift は同じような結果を達成するために max() と min() メソッドを使用して、より簡単なソリューションを提供します。

上の画像から、並べ替えの順序が増加していることが分かります。つまり、条件は小さい数値から大きい数値へと値を取得するように記述する必要があります。

let topScoreStudent = students.max(by: { $0.score < $1.score })
print(topScoreStudent?.name)
// Output: Optional("Kurt")
let lowestStudent = students.min(by: { $0.score < $1.score })
print(lowestStudent?.name)
// Output: Optional("Alice")

7. 特定の条件で配列要素を削除する

Swift の配列には、いくつかの remove メソッド が用意されています。指定された条件で要素または複数の要素を削除するには、これらの2つのメソッドを使用できます。

  1. removeAll(where:)

  2. 長い解決策は、出現のインデックスを見つけるために firstIndex を使用し、特定のインデックスで項目を削除するために remove(at:) を呼び出します。

removeAll() は項目を削除するのではなく、条件を満たす全ての項目を削除することに注意してください。

// Longer steps
if let index = students.firstIndex(where: { $0.name == "Bob" }) {
    students.remove(at: index)
}
print(students.map { $0.name })

if let index = students.firstIndex(where: { $0.score == 0 }) {
    students.remove(at: index)
}
print(students.map { $0.name })

// Remove all with condition
students.removeAll(where: { $0.name == "Rose"})
print(students.map { $0.name })

students.removeAll(where: { $0.score < 50 })
print(students.map { $0.name })

// Output:
// ["John", "Alice", "Rose", "Kurt", "Fatima", "Julie", "Patrick", "Spongebob"] ** Bob removed
// ["John", "Rose", "Kurt", "Fatima", "Julie", "Patrick", "Spongebob"]          ** Alice removed
// ["John", "Kurt", "Fatima", "Julie", "Patrick", "Spongebob"]                  ** Rose removed
// ["John", "Kurt", "Fatima", "Julie", "Patrick"]                               ** Spongebob removed

皆さん、よく頑張りました!

この記事があなたの開発スキルを向上させる助けになることを願っています。この記事を読んでくれてありがとう。フィードバックは大歓迎です。ハッピー・コーディング!

"学ぶこと、それがコーディングスキルを成長させる方法です。"

参考記事

https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html

https://docs.swift.org/swift-book/LanguageGuide/Closures.html

【翻訳元の記事】

7 Array Features That Every Swift Developer Should Know
https://medium.com/geekculture/7-array-features-every-swift-beginner-must-know-745a11b8f6f1

Discussion