謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

プログラム脳を鍛える数学パズル on python3

追記: とりま gist に置いてみた (2017/06/27

お題はこれで、目標は1日1個以上。

…ダレ無いといいけど…。

続きを読む

超久々に Python 弄ってた

AI 関連が実質 Python 一択で、数学系ライブラリもその表示も Python だとかなり揃ってたので、久々にやってみようとしてどハマりした記録。
何をしようとしたかというと、下記を Python で実装すればいいかなーとかとか漠然と考えてどハマりした。

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

どこにはまったかというと問題2。

問題内容は書籍を買うか、下記を見て欲しい。

white-azalea.hatenablog.jp

  1. Python だし、eval あるよねー使い方調べるついでに使って見るかー」
    → 9009 に * 突っ込むとしても 90*09 とかになるとダウンする。09 ってなんぞやー
  2. 「諦めて、* が必要な箇所で文字列区切って掛け算するか」
    → 変数タイポで 1h どハマり(実行時評価だから実行するまでわからないので単純なミスが見つからない)
  3. 「計算できたし正解を比較するか」
    → 久々にやってて問題文間違って覚えてて、「計算の前後で出た四桁数字が順不同で含まれてることじゃね?」と勘違いして実装。
    → 片方の文字列を1時づつ取り出して、もう片方に含まれるか?という判定をするが、122 - 124 でも true になる。
    → なら逆も比較したらええやんと思いきや、122 - 12 で結局OK判定になってしまう。
    → なので、片方の文字列を1時づつ取り出して、もう片方から1字づつ削除(immutable じゃなくて背中が痒く…)してみるも、 Java の String.replace 同様の replace メソッドを見つけたが、第3引数に指定がないと replaceAll 同等動作とか知らずにハマる。
    → 突破したら突破したで仕様違いに気づいて脱力…回文かよ…

で、色々やった挙句、こんな単純な問題に 3 時間も悩まされたという。

途中途中で Syntax error に悩まされたのもでかい。
TextMate2 を使っているが、やっぱ IDE なんかでリアルタイムに syntax チェックしてないとわからん。
加えて言えば、実行字型の為に、動かしてから死んでデバッグの後戻りがひどかった…

慣れの問題なのだろうか、例えば代入時に変数名が一時違った位でも、「新しい変数ができた」と認識されて平然と動いてしまう為、何が悪いか超追いかけづらかった…。

結局最後は全部関数にした…もう…関数型で…イイヨ。
たとえ…Python に… tail call recursive が実装されてなかったとしても…!

positions = [
    [1], [2], [3],
    [2, 1], [3, 2], [3, 1],
    [3, 2, 1]
]

def split(str, pos, stack):
    if len(pos) == 0:
        stack.append(str)
        return stack
    else:
        i = pos[0]
        stack.append(str[i:])
        return split(str[:i], pos[1:], stack)

from functools import reduce

def multiple(list):
    return reduce(lambda a,b: a * b, list)

def is_kaibun(left, right):
    return left == right[::-1]

for cur in range(1000, 9999):
    strCur = str(cur)
    for pos in positions:
        splitted = split(strCur, pos, [])
        result   = multiple(map(lambda v: int(v), splitted))
        if is_kaibun(strCur, str(result)):
            print(str(splitted) + " = " + str(result))
            print("success: " + strCur)

Java8 の Stream が物足りない人たちへ

www.vavr.io

言ってみれば、Scala 並の Collection を Java で提供するライブラリ。
何がいいって、Tuple とか Either 型もあるから、クソッタレな null や throw とおさらばできる。

その昔 javaslang (java.lang があるなら俗語があってもいいよね)と名乗ってた。
個人的にはこっちのセンスが好きだったんだけど…物言いでもはいりましたかね。

まぁケースバイケースで。

JUnit をもう少し管理者にみやすくしてみた

今日紹介するのはこれ。
Scala でザクッと作ってみた。

github.com

制作時間は調べ物 6h 、実装 4h か…
まだまだ精進が足りない。

こいつは先日書いた、JavaDoc を XML で吐き出すメモ - 謎言語使いの徒然 と、JUnit の結果をマージして出力するツールだ。
サンプルこんな感じ。

$ java -jar ut_converter.jar javadoc/javadoc.xml ut > result.html
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

で出てくるのがこんな感じ。

f:id:white-azalea:20170611130253p:plain

JUnit は Spec じゃ無いから、表現力が低い。
そのため、メソッド名は目安になるけど、それ単品ではテストレポートとして出すのが難しい。

そこで、Javadoc で細かくテスト内容書いておいたら、まとめて表示してくれるツールがどっかで要るなと。
2週間位前にリポジトリは作ってたけど、やっぱ平日に手を出す余裕ないね(汗

引数パースライブラリの SCOPT(3.6.0) 使ってみた

紹介するのはこれ

github.com

依存はこれだけ

libraryDependencies ++= Seq(
  "com.github.scopt" %% "scopt" % "3.6.0"
)

で、引数を格納するクラスをこんな風に用意して

import java.io.File

case class Config(javaDocXml: File, junitResultDir: File)

パース設定とかを用意する。

import java.io.File
import scopt.OptionParser

object ArgParser {

  val parser = new OptionParser[Config]("UTXmlConverter") {
    head("ut_converter", "1.0-SNAPSHOT")

    arg[File]("[JavaDoc XML path]")
      .required()
      .text("Path for XML file that using MarkusBernhardt/xml-doclet.")
      .action((f, c) => c.copy(javaDocXml = f))
      .validate(v => {
        if (!v.isFile) Left("Not a file.")
        else if (!v.getAbsolutePath.endsWith(".xml")) Left("Not a XML file.")
        else Right()
      })

    arg[File]("[UT XML dir path]")
      .required()
      .text("Path for unit test results directory path.")
      .action((f, c) => c.copy(junitResultDir = f))
      .validate(v => if (v.isDirectory) Right() else Left("Not directory."))

    help("help").text("print this usage text.")

    note(
      "This program requires XMLs that generated by MarkusBernhardt/xml-doclet (var 1.0.5)\n" +
        " and Junit test results XML files."
    )
  }

  def parse(args: Array[String]): Option[Config] = {
    parser
      .parse(args, Config(new File("docs.xml"), new File("ut_results")))
  }
}

そして、引数指定しないで実行すると…

Error: Missing argument [JavaDoc XML path]
Error: Missing argument [UT XML dir path]
Try --help for more information.

おーいいね。
help 読んでみても…

$ java -jar ut_converter.jar --help
ut_converter 1.0-SNAPSHOT
Usage: UTXmlConverter [options] [JavaDoc XML path] [UT XML dir path]

  [JavaDoc XML path]  Path for XML file that using MarkusBernhardt/xml-doclet.
  [UT XML dir path]   Path for unit test results directory path.
  --help              print this usage text.
This program requires XMLs that generated by MarkusBernhardt/xml-doclet (var 1.0.5)
 and Junit test results XML files.

オプション引数や、引数バリデーションも書けるし、なかなかいいですね。

sbt を jar にしてみた

つっても何の事は無い。

github.com

これ突っ込んだだけ。

project/plugins.sbt に下記を追加して

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.4")

build.sbt でざっくり指定するだけ。

name := "Example"

version := "1.0-SNAPSHOT"

scalaVersion := "2.11.8"

mainClass in assembly := Some("net.white_azalea.Application")

assemblyJarName in assembly := "example.jar"

これして sbt assembly するだけで、target/scala-2.11/example.jar が出来上がる。
以上。

JavaDoc を XML で吐き出すメモ

やりたい事が何かと言うと、外部プログラムにおいて、Java クラスのリスト取得と、そのドキュメントを引き抜きたいと考えた。

しかしながら、単純に javadoc のコマンドだけ実行すると、HTML ファイルが出てくる。
これは JavaDoc コマンドの仕様であり、基本動作となっていて、中間ファイルなども出てきていないようだ。

要するに javadoc コマンドの中でパースやら構築やら全部やってしまっていて、その間にあるだろう Javaクラス構成とそのドキュメント構造を引っこ抜く事がこのままだとできない。
でも当たり前だが、同じことをしたい人なんて絶対いるだろうと…むしろ居ない訳がなかろうと思ったのだ。

そして散々悩んだところ、どうも JavaDoc には Doclet なる機構が存在するらしい。
この Doclet とは、JavaDoc で読み取ったデータを出力する際のデータ整形に使われるようだ。

つまりこいつに XML 生成の Doclet 食わせてやれば、XML が吐き出されると思われた。
で、探して見たところ案の定。

github.com

そりゃそーだよなと、むしろない訳ないよなと。

って事でやってみた。

続きを読む