LoginSignup
1
2

More than 5 years have passed since last update.

Scalaに入門してみる (随時更新予定)

Last updated at Posted at 2018-12-29

概要

Scalaに入門してみたので、その軌跡を記録したいと思います。
(途中でやめてしまうかもしれないですが...)

はじめに

環境設定

MacでのScalaの環境設定は、良い記事がたくさんあるので「Mac Scala 環境構築」などで調べてみてください。
Scalaは 2.12.8 を利用しています (2018/12/29時点)

参考にしたサイト

S-99をやってみる

S-99というScalaの練習問題を解きながら、Scalaや関数型プログラミング言語への理解を深めていこうと思い、少しずつですが取り組んでみようと思います。

この記事の見方

やった問題は Githubに載せています。
ここでは、問題を解いた時点で発見のあったところを中心に記事にしたいと思います。

※ P28まで回答済 (2019/1/4)

S-99

P07

// P07 (**) Flatten a nested list structure.
// Example:
scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))
res0: List[Any] = List(1, 1, 2, 3, 5, 8)

複数階層になっているリストが混じっているリストをフラットにする、という問題です。

回答

Rubyであれば flatten で以下のように書けるので、同じ気持ちでいたのですが...
Scalaではエラーが出てしまいました🤔

irb(main):001:0> [[1, 1], 2, [3, [5, 8]]].flatten
=> [1, 1, 2, 3, 5, 8]

Scalaのflattenの定義を確認してみます。

def flatten[B]: List[B]
// [use case]
// Converts this list of traversable collections into a list formed by the elements 
// of these traversable collections.
// 
// The resulting collection's type will be guided by the static type of list. For example:

んー、まぁわからないんですけどねw 「Converts this list of traversable collections」と書いてあります。 traversableとはなんでしょうか..
Scalaの日本語ドキュメントによると、 走査可能 (Traversable)トレイトはコレクション階層の最上位に位置する。 と書いてありました。つまり、ArrayとかListとかmapやflatMapを使えるようなもののリストでないとダメなのでしょうか?
だとすると、1のような整数はNGということになりそうですよね。

scala> List(List(1,2,3), List(1,2,3)).flatten
res1: List[Int] = List(1, 2, 3, 1, 2, 3)

scala> List(List(1,2,3), Set(1,2)).flatten
res2: List[Int] = List(1, 2, 3, 1, 2)

scala> List(List(1,2,3), 1, 2).flatten
<console>:12: error: No implicit view available from Any => scala.collection.GenTraversableOnce[B].
       List(List(1,2,3), 1, 2).flatten
                               ^

(もう答え見てしまっていますが...w)
では、配列を生成してからflattenすればいいのでしょうか? (= flat + map = flatMap)

final def flatMap[B](f: (A)  GenTraversableOnce[B]): List[B]
// [use case]
// Builds a new collection by applying a function to all elements 
// of this list and using the elements of the resulting collections.

リストの各要素に対して、 引数f(A型の変数を引数にとり、 B型のGenTraversableOnce型を返す)をとり、B型のリストを生成する関数と見えます。
GenTraversableOnceとは、先ほどのTraversableの親戚のようなもの(多分)で、リストを生成すればよいみたいです。

ここで、引数として与えられているのは List(List(1, 1), 2, List(3, List(5, 8))) なので、以下のパターンがありそうです。

  1. Int型の配列
  2. Int型

なので、flatMapの内容を以下のようにしてあげたらよさそうでした。

def flatten(list: List[Any]): List[Any] = list flatMap {
  case head:List[_] => flatten(head)
  case e            => List(e)
}

ここで登場している head:List[_] というのは、 1行目で list flatMat { ... となっているので、listの中の1要素に対してのパターンマッチであり、 head:List[_] というのは「変数名: head」で、headの型が「List[_]」という意味です。つまり、リストが来たら再度自身を呼び出して次のパターンにマッチさせています。
最終的に List(List(1, 1), 2, List(3, List(5, 8)))List(List(1), List(1), List(2), List(3), List(5), List(8)) ということになり、それに対してflattenが呼び出されており (多分)、 List(1, 1, 2, 3, 5, 8) となります。

P22

// P22 (*) Create a list containing all integers within a given range.
// Example:
scala> range(4, 9)
res0: List[Int] = List(4, 5, 6, 7, 8, 9)

回答

object P22 {
  def range(from: Int, to: Int): List[Int] = {
    def rangeR(end: Int, ls: List[Int]): List[Int] = {
      if (from > end) ls
      else rangeR(end-1, end :: ls)
    }
    rangeR(to, Nil)
  }

  def main(args: Array[String]): Unit = {
    println(range(4, 9))
    println(range2(4, 9))
  }
}

scalaでは、関数内に関数を定義することができるようです。
Nested Methods

P28:a

// P28 (**) Sorting a list of lists according to length of sublists.
// a) We suppose that a list contains elements that are lists themselves. The objective is to sort the elements of the list according to their length. E.g. short lists first, longer lists later, or vice versa.
// Example:

scala> lsort(List(List('a, 'b, 'c), List('d, 'e), List('f, 'g, 'h), List('d, 'e), List('i, 'j, 'k, 'l), List('m, 'n), List('o)))
res0: List[List[Symbol]] = List(List('o), List('d, 'e), List('d, 'e), List('m, 'n), List('a, 'b, 'c), List('f, 'g, 'h), List('i, 'j, 'k, 'l))

回答

import P26.combinations

object P27 {
  def group3[A](list: List[A]): List[List[List[A]]] = {
    for {
      a <- combinations(2, list)
      b <- combinations(3, list diff a)
      c <- combinations(4, list diff b)
    } yield List(a, b, c)
  }.toList

  def main(args: Array[String]): Unit = {
    val list = List("Aldo", "Beat", "Carla", "David", "Evi", "Flip", "Gary", "Hugo", "Ida")
    group3(list).foreach(println)
  }
}

scalaのfor文も非常に強力だなと思いました(多分10%も理解できてない)
こちらの記事が非常に参考になりました。ありがとうございます。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2