前回のエントリで、複数の引数を受け取って、数値6個ならymパラメータ、数値8個ならymdパラメータ、
それ以外ならkeywordパラメータとして検索条件に指定するために
可変リストをあらかじめ3つ用意してパターンマッチで各要素をそれぞれのリストに追加していくようにしていたが、
partition という関数(TraversableLike トレイトのメソッドというのが正しいのかな?)を使うと
上手く振り分けられそうだったのでやってみた。
partition は「リストの要素の型を引数に取って真偽値を返す関数」を引数に取って
条件に合う要素を集めたリストと合わない要素を集めたリストのタプルを返す。
また、partition に渡す関数には Regex クラスの findFirstIn メソッドを使用したが、
これは文字列を取って Option[String] を返す。
Option 型は Haskell でいう Maybe みたいなもので、正規表現にマッチしない場合は None を返すようだ。
import scala.collection.mutable.ListBuffer
import scala.io.Source
import scala.xml.XML

import java.text.SimpleDateFormat

val source = Source.fromURL("http://api.atnd.org/events/?" + getParams(args))
val response = XML.loadString(source.mkString)

val orgFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
val showFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm")

response \\ "event" foreach { e =>
    println("『%s』\n  %s\n  %s\n" format(
	e \\ "title" text,
	showFormat.format(orgFormat.parse(e \\ "started_at" text)),
	e \\ "place" text))
}

def getParams(args:Array[String]):String = {
	val ymPattern = """^\d{6}$""".r
	val ymdPattern = """^\d{8}$""".r
	
	val (ymList, otherList) = args partition (ymPattern.findFirstIn(_) != None)
	val (ymdList, keywordList) = otherList partition (ymdPattern.findFirstIn(_) != None)
	
	val paramsList = new ListBuffer[String]
	if (!keywordList.isEmpty) {
		paramsList += "keyword=" + keywordList.mkString(",")
	}
	if (!ymList.isEmpty) {
		paramsList += "ym=" + ymList.mkString(",")
	}
	if (!ymdList.isEmpty) {
		paramsList += "ymd=" + ymdList.mkString(",")
	}
	
	paramsList.mkString("&")
}
こんな感じになった。
書き直したのは getParams の中のみ。
正規表現にマッチした場合 Some(String) が、マッチしない場合 None が返るので、
正規表現にマッチしたかどうかを None かどうかで振り分けている。
可変リストの多用が少しは解消され、前よりは良くなったように思う。
ただ、partition を2回行なっているのはもうちょっと何とかできる気がするなあ…。

【追記】「:::」を使用した改良版を書きました。

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .