will and way

ただの自分用メモを人に伝える形式で書くことでわかりやすくまとめてるはずのブログ

Swift4のDictionaryのアプデの目玉が公式ブログ?に掲載されてたので読んでみた

原文はこちら

Swift4ではDictionaryがより便利に使えるようになっているということで サンプルを見ていく

Grouping Values By a Key

Swift3系では

グループ機能がなく、かなりの手順を要していた

// Swift <= 3.1
var grouped: [GroceryItem.Department: [GroceryItem]] = [:]
for item in groceries {
    if grouped[item.department] != nil {
        grouped[item.department]!.append(item)
    } else {
        grouped[item.department] = [item]
    }
}
  1. まずグループの配列があるかチェック
  2. あれば配列についか
  3. なければ配列を作ってgroupedに登録

これがSwift4ではDictionaryのイニシャライザに用意され、1行で書くことができるようになりました。

// Swift >= 4.0
let groceriesByDepartment = Dictionary.init(grouping: groceries, by: { item in item.department })

このまま紹介しても味気ないので僕は下記のように使ってみました

extension Sequence {
    func group<Key>(by predicate: (Element) throws -> Key) rethrows -> [Key: [Element]] {
        return try Dictionary(grouping: self, by: predicate)
    }
}

let groceriesByDepartment = groceries.group(by: { item in item.department })
// [seafood: [{…}, {…}], bakery: [{…}, {…}], produce: [{…}, {…}, {…}]]

grouping対象はSequenceに準拠している必要があるということで、もはやSequeceに用意しちゃえばいいじゃん!と。

Transforming a Dictionary’s Values

Swift3まではmapすると、(key, value)形式で走査してましたがmapValueを使えば、valueだけを走査することができるようになりました。

なお、transformの対象はValueのみ。

let nameByDepartment = groceriesByDepartment.mapValues { items in
    items.map { item in
        item.name
    }
}

// [seafood: ["Salmon", "Shrimp"], bakery: ["Croissants", "Bread"], produce: ["Apples", "Bananas", "Grapes"]]

Uniquing Keys With

let pairs = [("dog", "🐕"), ("cat", "🐱"), ("dog", "🐶"), ("bunny", "🐰")]
let petmoji = Dictionary(pairs,
                         uniquingKeysWith: { (old, new) in new })
// petmoji["cat"] == "🐱"
// petmoji["dog"] == "🐶"

SequenceのElementの型がCompound Typeなのでこちらはextensionかけない…

Using Default Values

for item in [🍌, 🍌, 🍞] {
    cart[item, default: 0] += 1
}

下記でも解説されてますね

Swift 4の魅力の一面を3行で表す - Qiita

Merging Two Dictionaries Into One

var cart = [🍌: 1, 🍇: 2]
let otherCart = [🍌: 2, 🍇: 3]
cart.merge(otherCart, uniquingKeysWith: +)

この実装見ていて初めて気づいたんですが、closureとしてオペレータ渡せるんですね。
知らなかったので今後の実装に使えそう。

func +(left: T, right: T) -> T { }

冷静に考えると、+ operatorはinfixな関数なので、なるほどSwiftよくできてるな〜と感心した案件でした。