Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

先日 Swift 4 がリリースされました。みんな注目しているのは Codable など劇的にコーディングが楽になる新機能だと思いますが、ちょっとした便利な小技もあります。

そんな、 Swift 4 の小技の魅力の一面を 3 行にぎゅっと詰め込んだコードを思い付いたので紹介します。

// User の Array から、 team ごとの人数を集計する
let teamToCount: [String: Int] = users.reduce(into: [:]) { teamToCount, user in
  teamToCount[user.team, default: 0] += 1
}

これは、 UserArrayteam ごとに集計するコードで、次の二つの新 API を使っています。

Swift 3だと

もし、 Swift 3 で同じことを書こうとすると次のようなコードになるでしょう。

// Swift 3 の場合
var teamToCount: [String: Int] = [:]
for user in users {
  let team = user.team
  if let count = teamToCount[team] {
    teamToCount[team] = count + 1
  } else {
    teamToCount[team] = 1
  }
}

長いですね・・・。しかも、 teamToCount が無駄に var になってしまいました。

ちょっとした解説

どうして Swift 3 だと長くなってしまうかと言うと、 Dictionarysubscript を使おうとした部分で、キーに対応した値が存在しないケースを別で扱わないといけないからです。 Dictionary を使った集計というのは(少なくとも僕は)よく書く処理であり、他の言語を書いている場合も含めてストレスフルなパターンの一つです。それを、 default 値を与えられるようにし、 += と組み合わせて使えるというのが素晴らしいところです。

また、 Sequence から何かを組み立てるときに reduce は便利ですが、 Swift 3 までは Dictionaryreduce で組み立てる良い方法がありませんでした。新しい reduce(into:_:)inout な引数を持つ関数を渡すというアイデアでその点を見事に解決しています。

それぞれの API の詳しい説明は次の投稿を御覧ください。

group(by:) 的なメソッドがあればもっと簡単なんじゃないかという考え方もありますが、よりプリミティブで汎用性が高く、使い勝手の良い道具が用意されて、それを組み合わせてこれまで面倒だったケースに対応できたというところが僕が感動した点です。

動作するコード全体

検証用に書いた動作するコードの全体です。そのまま実行できます。

// 型の準備
struct User {
  var team: String
}

// 値の準備
let users = [
  User(team: "A"),
  User(team: "B"),
  User(team: "B"),
  User(team: "A"),
  User(team: "C"),
  User(team: "A"),
  User(team: "C"),
  User(team: "B"),
  User(team: "D"),
  User(team: "A"),
]

// 集計
let teamToCount: [String: Int] = users.reduce(into: [:]) { teamToCount, user in
  teamToCount[user.team, default: 0] += 1
}

// 出力
for (team, count) in (teamToCount.sorted { $0.key < $1.key }) {
  print("\(team): \(count)")
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away