Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

Arrayにおけるmap, flatMapの動作(swift3)

ググると引っかかるのか今だにswift2のドキュメントなので、swift3用のメモ

let a = [1, 2, 3]
let b = a.map { Array(repeating: $0, count: $0) }
print(b)
// [[1], [2, 2], [3, 3, 3]]

let c = [1, 2, 3]
let d = c.flatMap { Array(repeating: $0, count: $0) } 
// [1, 2, 2, 3, 3, 3]
print(d)

これはちゃんとメソッド通りの動作で安心。

enum Optional<Wrapped> の map, flatMapメソッド

swiftのソースでmapとflatMapというメソッドがよく出てくるのだが、このメソッド名からは想像できない動作をするのでメモしておく。 (メソッド名変えてくんないかな。。)

Optionalの定義を見ると次のようになっている。

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
  case none
  case some(Wrapped)
  public init(_ some: Wrapped)
  public init(nilLiteral: ())

  // mapメソッドはオプショナルではない値を返すクロージャを引数に取る。
  // 戻り値はオプショナル。
  public func map<U>(_ transform: (Wrapped) throws -> U)
      rethrows -> U?

  // flatMapメソッドはオプショナルの値を返すクロージャを引数に取る。。
  // 戻り値はオプショナル。
  public func flatMap<U>(_ transform: (Wrapped) throws -> U?)
      rethrows -> U?
}

mapの例

let a: Int? = Int("3")
let b: Int? = a.map { $0 * $0 }
print(b)
// Prints "Optional(9)"

let c: Int? = nil
let d: Int? = c.map { $0 * $0 }
print(d)
// Prints "nil"

flatMapの例

let a: Int? = Int("3")
let b: Int? = a.flatMap { x -> Int? in
  let (result, overflowed) = Int.multiplyWithOverflow(x, x)
  return overflowed ? nil : result
}
print(b)
// Prints "Optional(9)"

mapもflatMapもどちらも同じような動作をするが、クロージャの戻り値がnilになる場合がある時はflatMapを使い、それ以外はmapを使うという使い分けになるだろうか。

swift 2つの連続する矢印

swiftでこんなソースが出てきた。-> が2つ連続しているが意味がすぐには分からない。

func multi(val:Int) -> (val:Int) -> Int {
    return { a_val in return a_val * val }
}

省略されている()を書くとこうなる。

func multi(val:Int) -> ((val:Int) -> Int) {
    return { a_val in return a_val * val }
}

これは省略できない方が可読性がいいのではないだろうか。

swift ComparableIndex

swiftのComparableプロトコルはEquatableプロトコルを継承しているので、Comparableと同じことがしたいがEquatableは実装したくないという時に使えない。
その場合、Comparableに相当するプロトコルだけを自分で実装すれば良い。

public protocol ComparableIndex {
    static func LessIndex(_ lhs: Self, _ rhs: Self) -> Bool
}

extension Array where Element : ComparableIndex {
    mutating func sortWithIndex() {
        self.sort(by: { (a, b) in Element.LessIndex(a, b) })
    }
}

これは、Arrayを独自の関数LessIndexで比較してソートする関数を追加するエクステンションである。