3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

整数配列の連続区間をグループ化するアレをScalaでやってみた

Posted at

先行事例

整数配列の連続区間をハイフンで連結してグループ化する定番のアレを「Scalaでできないか?」って話題で盛り上がってたので、挑戦してみました。

たどり着いた答え(数字のみ)

scala> val sample = Seq(1,2,3,4,5,8,9,10,13,14,20,22)
sample: Seq[Int] = List(1, 2, 3, 4, 5, 8, 9, 10, 13, 14, 20, 22)

scala> sample.foldLeft(Seq((1, 0)))((z, n) => if((z.head._2 + 1) == n) (z.head._1, n) +: z.tail else (n, n) +: z).reverse
res0: Seq[(Int, Int)] = List((1,5), (8,10), (13,14), (20,20), (22,22))

解説

ぶっちゃけ関数型まだ慣れきってなくてちゃんと正しい処理してるかわからないのだけれども。たぶん、大丈夫。

ポイント

  • foldLeft
  • リストを左から右へ畳み込む高階関数
  • +:
  • コレクションの先頭に要素を追加する
  • tail
  • 先頭を除いた残りのコレクションを返す

何をしてるか

前提として:与えられる数値のリストはソートされてるものとします。(されてなければソートしてください)

連続する数値をその最小値と最大値で表すタプル (min, max) を作って行きます。

まず最初にfoldLeftの初期値として1個目を与えてます。これは本当なら連続を確かめたいListの (最小値, 最小値-1) じゃないといけないと思う。いくつの連続ができるかわからないですがとりあえずタプルを含むSeqにしてます。

さて、このタプルのSeqが z 、そして一つ目の要素が n として与えられるので、先頭に入っているタプルの max に1を足してみてnと比較します。もし等しいなら前の数値より一つ大きいということになるので、数値が連続していると判断します。
数値が連続していた場合にはSeqの先頭のタプルを破棄して、代わりに最小値はそのままだが最大値をnに置き換えたタプルを作って、先頭にくっつけます。

もし数値が連続していなかった場合は、既存のタプルはそのままに新しくnからnまでの連続した数値、ということにしてタプルを生成して、同じく先頭にくっつけます。

さて、一つの要素について処理を終えると、そこには例のタプルをいくつか含んだSeqとまだ処理されてない要素が残ります。
このSeqに対してまたmaxと次のnを比較する処理を、要素が空になるまでひたすらに繰り返しています。

最終的に、最大値と最小値を表すタプルをいくつか含んだSeqが完成します。

varとか使いたくなかったので、タプルを作っては捨て、作っては捨て、とカジュアルにぶん投げてるあたりが無理矢理で気に入ってます。

最後に

scala> sample.foldLeft(Seq((1, 0)))((z, n) => if((z.head._2 + 1) == n) (z.head._1, n) +: z.tail else (n, n) +: z).reverse.map(t => if(t._1 != t._2) t._1 + "-" + t._2 else t._1).mkString(",")
res6: String = 1-5,8-10,13-14,20,22
3
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?