by shigemk2

当面は技術的なことしか書かない

zipAllがやっとなんとなくわかってきた

概要

zipAllってなんだったけ…サンプルコードを漁ってもよくわかりません。

Scalaコレクションメソッドメモ(Hishidama's Scala collection method Memo)

サンプルコードをちょっといじってみる

上のサンプルコードだけ読んでみても良くわからないので、カスタマイズしてみる。もともとは2つのリストをドッキングさせて1つのリストにするやつです。

scala> List(1,2,3,4).zip(List("a","b","c","d"))
res6: List[(Int, String)] = List((1,a), (2,b), (3,c), (4,d))

普通のzipだと2つのリストの要素数が同じじゃないと余った値は捨てられる。下の例だとeが捨てられる。最初のリストと後のリストの要素数がそれぞれ4と5なので、5番目の要素は切り捨てられてしまうから。

scala> List(1,2,3,4).zip(List("a","b","c","d","e"))
res7: List[(Int, String)] = List((1,a), (2,b), (3,c), (4,d))

で、要素数4、要素数5のリストをzipしたいときはどうするかというと、zipAllを使うわけで。 1番目の引数でリストを、2番めの引数で最初のリストの要素が足りない時の値を、3番目の引数であとのリストの要素が足りない時の値を、それぞれ設定する。

scala> List(1,2,3,4).zipAll( List('a,'b,'c,'d,'e), 99, 'z)
res4: List[(Int, Symbol)] = List((1,'a), (2,'b), (3,'c), (4,'d), (99,'e))

scala> List(1,2,3,4).zipAll( List('a,'b,'c), 99, 'z)
res5: List[(Int, Symbol)] = List((1,'a), (2,'b), (3,'c), (4,'z))

たぶんzipAllの2番め3番目の値は動的に設定できるのかもしれないけども。。

ソースコード

で、ソースコードを読んでみると、そんな感じのことが書いてありました。リストをぐるぐる回してタプルを入れているのですが、リストが終わっていたら第二第三引数で設定した値をタプルとして入れるような実装になっています。

  def zipAll[B, A1 >: A, That](that: GenIterable[B], thisElem: A1, thatElem: B)(implicit bf: CanBuildFrom[Repr, (A1, B), That]): That = {
    val b = bf(repr)
    val these = this.iterator
    val those = that.iterator
    while (these.hasNext && those.hasNext)
      b += ((these.next(), those.next()))
    while (these.hasNext)
      b += ((these.next(), thatElem))
    while (those.hasNext)
      b += ((thisElem, those.next()))
    b.result()
  }

scala/IterableLike.scala at v2.11.7 · scala/scala · GitHub

まとめ

  • サンプルコードは見るだけではなく自分でいじってみる
  • できればソースコードも読む