Language detail: Scala

Coverage: 92.14%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

タブ区切りデータの処理 (Nested Flatten)

あまりScalaらしくありませんが...。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
object Tsv {
  
  def tsv(text:String) : Unit = {
    import scala.io.Source
    val lines = Source.fromString(text).getLines
    print(lines.next)
    val data = lines.map({s:String => s.split("\t")})
    val lst = List.fromIterator(data).sort({(a:Array[String], b:Array[String]) => Integer.parseInt(a(0)) < Integer.parseInt(b(0))})
    for (line <- lst) {print(line(0) + "\t" + line(1) + "\t" + line(2) + "\t" + line(3))}
  }
  
  def main(args : Array[String]) : Unit = {
    val testData = "ID\tSurname\tForename\tAge\n1\tSato\tHanako\t17\n0\tSuzuki\tTaro\t18\n"
    tsv(testData)
  }
}
変数の初期値 (Nested Flatten)

 scalaの場合変数宣言時に値を設定する必要があるので,未初期化時に値を設定するやり方は用意されていません。Option型は用意されているので,Noneが設定されている場合に限り値を設定する処理を参考までに挙げておきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class DefinedOr[T] {
    var    _v:Option[T] = None
    def this(n:T) = { this(); this.v = n }
    def v:Option[T] = _v
    def v_=(v:T) = { _v = Some(v) }
    def ||=(n:T) = { v = v match { case None => n; case Some(x) => x } }
}
object Main {
    def main(args:Array[String]) = {
        var    d:DefinedOr[Int] = new DefinedOr
        println(d.v)
        d ||= 0
        println(d.v)
        d ||= 1
        println(d.v)
        d = new DefinedOr(2)
        println(d.v)
        d ||= 0
        println(d.v)
    }
}
2^i * 3^j * 5^k なる整数 (Nested Flatten)

 #7638と#7671のやり方で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import    scala.collection.immutable.SortedSet
import    scala.collection.immutable.TreeSet
abstract class CHammingNumbers {
    def take(n:Int):List[Int]
}
class CHammingNumbersG extends CHammingNumbers {
    def next(s:List[Int],h:List[Int]):Tuple2[List[Int],List[Int]] = {
        val    m:List[Int] = s.zip(List(2,3,5)).map { v => h.apply(v._1)*v._2 }
        val    n:Int = m.sort { (a,b) => a < b }.head
        (s.zip(m).map { v => (v._2 == n) match { case true => v._1 + 1; case _ => v._1 } },h+n)
    }
    def take(n:Int,s:List[Int],h:List[Int]):Tuple2[List[Int],List[Int]] = n match {
            case 0 => (s,h)
            case _ => next(s,h) match { case v => take(n-1,v._1,v._2) }
        }
    def take(n:Int):List[Int] = take(n-1,List(0,0,0),List(1))._2
}
class CHammingNumbersS extends CHammingNumbers {
    def next(c:SortedSet[Int]):Tuple2[Int,SortedSet[Int]] = (c.firstKey,(TreeSet(c.firstKey*2,c.firstKey*3,c.firstKey*5)++(c-c.firstKey)))
    def take(n:Int,c:SortedSet[Int]):List[Int] = n match {
            case 0 => List()
            case _ => next(c) match { case v => v._1::take(n-1,v._2) }
        }
    def take(n:Int):List[Int] = take(n,TreeSet(1))
}
object HammingNumbers {
    def main(args:Array[String]):Unit = {
        try {
            val    n:Int = args.length match {
                case 1 => args(0).toInt
                case _ => 100
            }
            List(new CHammingNumbersG,new CHammingNumbersS).foreach { h => println(h.take(n).mkString("\n")) }
        } catch {
            case e => e.printStackTrace
        }
    }
}

 Streamを使って書いてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
object HammingNumbers {
    def from(n:Int):Stream[Int] = Stream.cons(n,from(n+1))
    def hammings(s:Stream[Int]):Stream[Int] = {
        def divide(n:Int,b:Int):Int = (n % b == 0) match {
                case false => n
                case _ => divide(n/b,b)
            }
        Stream.cons(s.head,hammings(s.tail.filter { n => List(2,3,5).foldLeft(n) { (v,b) => divide(v,b) } == 1 }))
    }
    def hammings():Stream[Int] = hammings(from(1))
    def main(args:Array[String]):Unit = {
        try {
            val    n:Int = args.length match {
                case 1 => args(0).toInt
                case _ => 100
            }
            println(hammings().take(n).mkString("\n"))
        } catch {
            case e => e.printStackTrace
        }
    }
}

 [1..100]>>=penさんの投稿を参考に書いてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CHummingNumbers {
    def next(c:Int):Int = (BigInt(30).pow(c) % c).intValue match {
            case 0 => c
            case _ => next(c+1)
        }
    def take(n:Int,c:Int):List[Int] = n match {
            case 0 => List()
            case _ => next(c) match { case v => v::take(n-1,v+1) }
        }
    def take(n:Int):List[Int] = take(n,1)
}
object HummingNumbers {
    def main(args:Array[String]):Unit = {
        try {
            val    n:Int = args.length match {
                case 1 => args(0).toInt
                case _ => 100
            }
            println((new CHummingNumbers).take(n).mkString("\n"))
        } catch {
            case e => e.printStackTrace
        }
    }
}
LL Golf Hole 9 - トラックバックを打つ (Nested Flatten)

 scalaで。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import    java.io._
import    java.net._
val    c = (new URL("http://ll.jus.or.jp/2008/blog/archives/38/trackback")).openConnection.asInstanceOf[HttpURLConnection]
c.setRequestMethod("POST")
c.setDoOutput(true)
val    o = new OutputStreamWriter(c.getOutputStream)
o.write("title=LL+Golf+Hole+9&excerpt=trackback+from+LL+Golf+Hole+9.&url=http://ja.doukaku.org/207/&blog_name=LL+Golf+Hole+9")
o.flush
o.close
val    i = new BufferedReader(new InputStreamReader(c.getInputStream))
while (i.ready) {
    println(i.readLine)
}
c.disconnect
与えられた並べ替えを実現するあみだくじの生成 (Nested Flatten)

 ソートを掛ける方法で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class CGhostLeg(g:List[Int]) {
    val    s:List[Int] = g.sort { (a,b) => a < b }
    var    p:List[List[Boolean]] = List()
    def create:CGhostLeg = {
        def _calc(c:List[Int],r:Tuple2[List[Int],List[Boolean]]):Tuple2[List[Int],List[Boolean]] = c match {
                case List() => r
                case h::List() => (r._1+h,r._2)
                case h::t => h.compare(t.head) match {
                        case p if p > 0 => _calc(c.slice(2).asInstanceOf[List[Int]],(r._1+c.apply(1)+h,r._2+true++(t match { case h::List() => List(); case _ => List(false) })))
                        case _ => _calc(t,(r._1+h,r._2+false))
                    }
                case _ => r
            }
        def _step(c:List[Int]):Unit = {
            val    n = _calc(c,(List(),List()))
            p = n._2::p
            if (!n._1.zip(s).filter { d => d._1 != d._2 }.isEmpty) _step(n._1)
        }
        _step(g)
        this
    }
    def print:Unit = {
        def _join(d:String,l:List[String]):String = l.head + l.tail.foldLeft("") { (s,e) => s + d + e }
        println(_join(" ",s.map { e => e.toString }))
        p.foreach { l =>
            println(_join("|",""::(l.map { e => e match { case true => "-"; case _ => " " } })+""))
        }
        println(_join(" ",g.map { e => e.toString }))
    }
}

object GhostLeg {
    def main(args:Array[String]):Unit = {
        try {
            var    g:List[Int] = args.length match {
                case 0 => List(3,5,2,4,0,1)
                case _ => args.toList.map { s => s.toInt }
            }
            (new CGhostLeg(g)).create.print
        } catch {
            case e => e.printStackTrace
        }
    }
}
魔方分割数 (Nested Flatten)

 Pentium1.6GHzの端末で17分少し掛かりました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import    java.text.SimpleDateFormat
import    java.util.Calendar

class CMagicNumber(n:Int) {
    val    m:Int = n * n
    val    a:Int = n * (n * n + 1) / 2
    def calc:Int = {
        def _calc(p:Int,c:Int,s:Int,r:List[Int],g:Int):Int = r match {
                case List() => g + 1
                case _ => c match {
                        case 0 => _calc(r.head,1,r.head,r.tail, g)
                        case _ => r.filter { d => d > p }.foldLeft(g) { (g,d) =>
                                ((c == n - 1) && (s + d == a)) match {
                                    case true => _calc(0,0,0,r.filter { e => e != d },g)
                                    case _ => (d + s >= a) match {
                                            case true => g
                                            case _ => _calc(d,c + 1,s + d,r.filter { e => e != d },g)
                                        }
                                }
                            }
                    }
            }
        _calc(0,0,0,(1 to m).toList,0)
    }
}
object MagicNumber {
    def printTime:Unit = println((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(Calendar.getInstance.getTime))
    def main(args:Array[String]):Unit = {
        try {
            printTime
            printf("result:%d\n",(new CMagicNumber(args.length match { case 1 => args(0).toInt; case _ => 5 })).calc)
            printTime
        } catch {
            case e => e.printStackTrace
        }
    }
}
文字列型日時ののN秒後時間取得 (Nested Flatten)

 Javaと余り変わりませんがscala版を。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import    java.text.DateFormat
import    java.text.ParseException
import    java.text.SimpleDateFormat
import    java.util.Calendar

object DateEx {
    val    formatter:DateFormat = new SimpleDateFormat("yyyyMMddHHmmss")
    def DateEx(date:String,diff:Int):String = {
        val    calendar:Calendar = Calendar.getInstance
        calendar.setTime(formatter.parse(date))
        DateEx(calendar,diff)
    }
    def DateEx(diff:Int):String = DateEx(Calendar.getInstance,diff)
    def DateEx(calendar:Calendar,diff:Int):String = {
        calendar.add(Calendar.SECOND,diff)
        formatter.format(calendar.getTime)
    }
    def main(args:Array[String]):Unit = {
        try {
            args.length match {
                case 2 => println(DateEx(args(0),args(1).toInt))
                case 1 => println(DateEx(args(0).toInt))
                case _ => println(DateEx("20080827235925",40))
            }
        } catch {
            case ex:ParseException => println("invalid date format.")
            case ex => ex.printStackTrace
        }
    }
}
tailの実装 (Nested Flatten)

 オプションの処理にかなり場所をとられてしまっていますが...。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import    java.io.FileNotFoundException
import    java.io.File
import    java.io.FileInputStream
import    scala.collection.mutable.HashMap

class InvalidArgumentException extends Exception {}

class GetOpt(f:String) {
    var    _params:List[Tuple2[String,Boolean]] = null
    var    _opt:HashMap[Any,Any] = null
    var    _rest:Array[String] = null
    
    _params = f.toList.foldLeft(List[Tuple2[String,Boolean]]()) { (l,c) =>
        c match {
            case ':' => l match {
                case List() => throw new InvalidArgumentException
                case h::r => (h._1,true)::r
            }
            case k => (k.toString,false)::l
        }
    }.reverse
    
    def parse(a:Array[String]):GetOpt = {
        def _parse(o:HashMap[Any,Any],l:List[String]):Tuple2[HashMap[Any,Any],List[String]] = l match {
            case List() => (o,List())
            case h::r => h.toList match {
                case '-'::k => {
                    _params.find { e => e._1 == new String(k.toArray) } match {
                        case Some(Tuple2(_,true)) => {
                            if (r.size == 0) throw new InvalidArgumentException
                            o.update(new String(k.toArray),r.head)
                            _parse(o,r.tail)
                        }
                        case Some(Tuple2(_,false)) => {
                            o.update(new String(k.toArray),true)
                            _parse(o,r)
                        }
                        case _ => throw new InvalidArgumentException
                    }
                }
                case _ => (o,l)
            }
        }
        _parse(new HashMap[Any,Any],a.toList) match {
            case Tuple2(o,r) => { _opt = o; _rest = r.toArray }
        }
        this
    }
    
    def getopt(k:String):Any = _opt.isDefinedAt(k) match {
        case true => _opt.apply(k)
        case _ => false
    }
    
    def rest:Array[String] = _rest
}

class CTail(n:Int,f:Boolean,i:File) {
    
    val    s:FileInputStream = new FileInputStream(i)
    
    def this(o:GetOpt) =this(o.getopt("n") match { case Some(false) => 10; case n => n.asInstanceOf[String].toInt },o.getopt("f").asInstanceOf[Boolean],new File(o.rest.apply(0)))
    
    def tailn:Unit = {
        
        val    BUF_SIZE:Int = 4096
        val    e:Long = i.length
        
        def _tailn(p:Long,n:Int,b:Array[Byte]):Array[Byte] = {
            var    t:Array[Byte] = null
            var    l:Int = n
            (p > BUF_SIZE) match {
                case true => {
                    t = new Array[Byte](BUF_SIZE)
                    s.getChannel.position(p - BUF_SIZE)
                    s.read(t,0,BUF_SIZE)
                }
                case _ => {
                    t = new Array[Byte](p.toInt)
                    s.read(t,0,p.toInt)
                }
            }
            t = t.reverse.takeWhile { c => if (c == '\n') l = l - 1; (l > 0) }.reverse
            ((p <= BUF_SIZE) || (l == 0)) match {
                case true => t ++ b
                case _ => _tailn(p - BUF_SIZE, l, t ++ b)
            }
        }
        
        print(new String(_tailn(e, n, new Array[Byte](0))))
        s.getChannel.position(e)
    }
    
    def tailf:Unit = {
        def _tailf(b:List[Byte]):List[Byte] = {
            val    c:Int = s.read
            (c >= 0) match {
                case true => _tailf(b + c.toByte)
                case _ => b
            }
        }
        print(new String(_tailf(List[Byte]()).toArray))
        Thread.sleep(100)
        tailf
    }
    
    def tail:CTail = {
        tailn
        if (f) tailf
        this
    }
    
    def close:Unit = s.close
}

object Tail {
    def main(args:Array[String]):Unit = {
        try {
            val    o:GetOpt = new GetOpt("n:f").parse(args)
            (new CTail(o)).tail.close
        } catch {
            case e:InvalidArgumentException => println("usage: scala Tail [-n <number of lines>] [-f] file")
            case e:FileNotFoundException => print("file not found.")
            case e:Exception => e.printStackTrace
        }
    }
}
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)

scalaで書く甲斐の無い感じのソースですが...。

1
val v=args(0);val w=(v.size-1)/3;printf("%.1f%c",v.toDouble/Math.pow(1000,w)," kMGTPEZY"(w))
LL Golf Hole 8 - 横向きのピラミッドを作る (Nested Flatten)

インタプリタ起動もできるのですねぇ...。知りませんでした。

1
val n=readInt;for(i<-(-n+1 to n-1))println("*"*(n-i.abs))
LL Golf Hole 6 - 10進数を2進数に基数変換する (Nested Flatten)
効率無視、副作用なし、ユーティリティメソッドを使わないを目標に作っています。
scala h6.scala 1234 などで動作させます。
1
2
def b(i:Int,s:String):String=if(i>0) b(i/2,""+(i%2)+s) else s
println(b(args(0).toInt,""))
LL Golf Hole 1 - tinyurl.comを使ってURLを短縮する (Nested Flatten)
かなり無駄なバージョン。
GETですけどAPIを使わずにTinyURLを取得して、Regexで抜き出してます。
scala h13.scala で動かします。
1
2
3
4
5
import io._
val url="http://ll.jus.or.jp/2008/info/xgihyo"
val t=new StringBuilder;for(c<-Source.fromURL("http://tinyurl.com/create.php?url="+url))t.append(c);
val r="""(?is).*characters:\s+<blockquote><b>([^\s]*)</b><br>.*</blockquote>.*""".r
t.toString match{case r(tu)=>println(tu) case _ =>}
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)
サンプルと同じく1000で単位を揃えています。
いつものごとくひねりはありません。再帰呼出でループを表現しています。
あまり大きな数になると表示がおかしくなります:-)。
scala h7.scala 1234.5 で動作させます。
1
2
3
4
val b=args(0).toDouble
val u=" kMGTPEZY"
def p(d:Double,c:Int){if(d<1000D||c==(u.length-1))printf("%.1f%c",d,u(c))else p(d/1000D,c+1)}
p(b,0)
LL Golf Hole 5 - 最上位の桁を数え上げる (Nested Flatten)
効率は無視、再帰呼出でループを表現してみました。
例のごとくひねりはありません。
表示すべき数字は文字列で生成してたりして、かなり卑怯な気がします(^^;。
scala h5.scala で実行します。
1
2
3
4
5
val n=args(0).toInt
def p(i:Int,c:Int){
  val v=(""+i+("0"*c)).toInt;if(v<=n){println(v);if(i<9)p(i+1,c)else p(1,c+1)}
}
p(0,0)
LL Golf Hole 1 - tinyurl.comを使ってURLを短縮する (Nested Flatten)
scala.io.Sourceを使ってストリームを出力してみる。
Scalaはscalaパッケージから相対的に名前空間にアクセスできるのでscala.io.Sourceではなくてio.Sourceでも問題ない。
なおSourceはソースファイルを読み込むためのクラスであるため本来の使い方じゃないし、文字エンコードもutf-8をデフォルトにしているので、アレではある。
scala h1.scala で実行。
1
for(c<-io.Source.fromURL("http://tinyurl.com/api-create.php?url=http://ll.jus.or.jp/2008/info/xgihyo")) print(c)
LL Golf Hole 2 - 文字列に含まれる単語の最初の文字を大文字にする (Nested Flatten)

短い解答はもうあるのでRegexにこだわって。capitalizeあるのか。というわけでcapitalizeバージョン。

1
for(a<-"\\w+\\s*".r.findAllIn(args(0)))print(a.capitalize)
LL Golf Hole 4 - 文章から単語の索引を作る (Nested Flatten)
かなり正攻法に作ってみました。ひねりなしです。
ファイルの読み込みにscala.io.Sourceを使いUTF-8で行ごと読んでいます。語句は単純にRegexで検索して取得して、それらを辞書に追加しています。
行番号取得が面倒だったのでIterator#zipWithIndexを使いました。
scala h4.scala で実行です。
1
2
3
4
5
6
import collection._
import collection.mutable._
val d=new HashMap[String,Buffer[Int]]
for((l,i)<-io.Source.fromURL("http://www.gnu.org/licenses/gpl.txt").getLines.zipWithIndex)
  for(w<-"\\w+".r.findAllIn(l))d.put(w,(if(d.contains(w))d(w)else new ArrayBuffer[Int])+(i+1))
println(d)
LL Golf Hole 3 - 13日の金曜日を数え上げる (Nested Flatten)
今回は結構まじめに実装してみました。
副作用のある操作は結構あるような気はしますが(Calendar周り)、なるべく副作用をさけ、かつ、再起呼び出しでカウントしてみました。
1
2
3
4
5
6
7
8
9
import java.util._
import java.util.Calendar._
def ci=Calendar.getInstance
val f=new java.text.SimpleDateFormat("yyyy-MM-dd")
val c=ci
val e={val v=ci;v.setTime(f.parse("2013-12-31"));v}
def fri={c.set(DAY_OF_MONTH, 13);c.get(DAY_OF_WEEK)==FRIDAY}
def fs(s:Int):Int=if(c.after(e)) s else{c.add(MONTH, 1);if(fri){println(f.format(c.getTime));fs(s+1)}else fs(s)}
println(fs(if(c.get(DAY_OF_MONTH)>=13&&fri) 1 else 0))
next >>

Index

Feed

Other

Link

Pathtraq

loading...