勉強メモ1
Rubyは以前遊びぐらいでしか触ったことがありませんが、
今回勉強したいと思い、学習を始めることになりました。
ただ、以前のように分厚い本を買って、表紙(まえがき)から最後の隅々まで
読んで写経することはしないつもりです。
時間を節約し、効率的に勉強したいと思います。
その方法として、既存のプログラミング言語に共通しそうな部分は除いて
Rubyにしかないものだけを勉強する、差分学習を取ります。
この記事はその学習メモです。
文字列中の変数
"#{変数名}"
コメント
- 1行 : #
- ブロック =begin ~ =end
定数
大文字。変更不可能。
多重代入
q, a, z = 1, 2, 3 q, a, *z = 1, 2, 3, 4, 5 # zには配列として代入。1, 2, [3, 4, 5] q, a = 0, 1 q, a = b, z ar = [3,4] q,a = ar # 3, 4 ar = [1, [2, 3], 4] q, (a1, a2), z = ar # 1, 2, 3, 4
分岐
if修飾子とunless修飾子
文の右にifやunlessを書くことができる。ミニif文、ミニunless文ってことか。
a = 1 "Hi" if a > 1 # nil "Man" if a == 1 # Man "Hoi" unless a > 1 # Hoi
===
==に似ているが、左辺がリテラル(クラス、数値、文字列など)の場合、右辺との比較を柔軟に行う。
例えば、String == "a"だと、false。String === "a"だと、"a"がStringクラスのインスタンスという比較を行い、trueがリターンされる。
同一性
オブジェクトの値を比較するなら、==を使えばいい。厳密にオブジェクトの同一性を比較するなら、eql?を使う。
Javaとは反対ですね。
繰り返し
- untilはwhileの反対。
- nextはJavaのcontinue。
- redoは同じことをもう一回繰り返す。
times
10.times do print "Duke" end
配列
names = ["Duke", "Foo"] names.each do |n| puts n end
ハッシュ
person = { name: "Duke", job: "Engineer" } person.each do |key, value| puts "#{key}: #{value}" end
ブロック
1行にまとめるときは{ ... }、複数行に分ける場合、do ... end
メソッド
- 最後にreturn文は省略してもよい。
- 可変長引数は引数に*argsと書く。
キーワード引数
引数名:デフォルト値
def m1(q:1, a:2, z:3) q + a + z end m1(z:5,q:3) # 10
ブロック付きメソッド
def m1 puts "Hello!" yield # これがブロックを実行する。 end m1 do puts "Hey Duke!" end # Hello! # Hey Duke!
引数がハッシュの場合、{}を省略可能
def m(q) q end m({ "n" => "d", "t" => 5 }) # { "n" => "d", "t" => 5 } m("n" => "d", "t" => 5) # { "n" => "d", "t" => 5 } m(n: "d", "t": 5) # { "n" => "d", "t" => 5 }
クラス
アクセスメソッド
getter, setterのようなもの。
一々メソッドを定義してもいいが、getter/setterの数が多いと、面倒。
代わりに以下のものを使えばgetterとsetterを自動生成してくれる。
attr_reader :変数名
getter
attr_setter :変数名
setter
attr_accessor :変数名
getter + setter
クラスメソッド
class << オブジェクト ~ end形式がある。
オブジェクトにクラス名を指定すると、以下の例のようにクラスメソッドになる(Classクラスのインスタンスにメソッドを追加)。
しかし、オブジェクトに特定インスタンス変数を指定すると、そのインスタンスのみにメソッドが追加される。
まるでJavascriptでオブジェクトに自由にメソッドを追加できるのと同じ感じだ。
# クラス内で定義 class DukeLab class << self def classMethod1 "Hey" end end end DukeLab.classMethod1 # Hey # 特異クラス形式で定義。既にDukeLabクラスが定義されなければならない。 class << DukeLab def classMethod2 "You!" end end DukeLab.classMethod2 # You! # クラスの外から定義 def DukeLab.classMethod3 "Man!" end DukeLab.classMethod3 # Man! # クラス内で定義 class DukeLab def self.classMethod4 "Woman!" end end DukeLab.classMethod4 # Man!
定数
クラス名::変数名
アクセス制限
何も指定しなければ、public。
public, private, protectedキーワードを使ってアクセス制限を定義できる。
class DukeTest def m1 "Duke1" end public :m1 #デフォルト def m2 "Duke2" end private :m2 end dt = DukeTest.new dt.m1 dt.m2 # エラー
まとめてprivateにする
class DukeTest def m1 "Duke1" end private # これより下はprivate def m2 "Duke2" end end
getだけ可能にする。
class DukeTest attr_accessor :q, :a private :q=, :a= # xとyにsetできないようにする。 def initialize(q, a) @q, @a = q, a end end dt = DukeTest.new dt.q dt.q = 8 # エラー
継承
class クラス < スーパークラス
モジュール
Scalaのtrait、Javaのdefault interfaceって感じ?
クラスでinclude モジュール名すると、そのクラスにモジュールの全てのメソッドが追加される。
モジュールをクラスに入れることをMixinという。
module Mod1 def m1 "variable : #{@q}" end end class Duke include Mod1 def initialize(q) @q = q end end d = Duke.new(5) d.m1 # variable : 5
Object.extend
特定オブジェクトにモジュールをMixinする。
module Mod1 def m1 "variable : #{@q}" end end class Duke def initialize(q) @q = q end end d1 = Duke.new(8) d1.extend(Mod1) d1.m1 # variable : 8
extendでクラスメソッドを追加
module Mod1 def m1 "Hi!" end end module Mod2 def m2 "Man!" end end class Duke extend Mod1 #クラスメソッド include Mod2 #インスタンスメソッド end d1 = Duke.new d1.m1 # エラー。インスタンスメソッドではない。 Duke.m1 # Hi! d1.m2 # Man! Duke.m2 # エラー。クラスメソッドではない。
演算子
範囲演算子
Range.new(x, y)又はx..yを使う。
for i in 1..10 puts i end (1..10).to_a # 1,2,3,4,5,6,7,8,9,10 (1...10).to_a # 1,2,3,4,5,6,7,8,9 yを除く。
演算子定義
class Apple attr_reader :n, :p def initialize(n, p) @n = n @p = p end def +@ # 単項演算子の場合、後尾に@をつける。 "Plus" end def +(other) self.class.new(n + other.n,p + other.p) end def inspect "n : #{n}, p : #{p}" end end a = Apple.new(1, 10) b = Apple.new(2, 20) +a # "Plus" a + b # n : 3, p : 30
例外
キーワードが違うだけで殆どJavaと同じ。
begin # try ... rescue => ex # catch ... retry # beginに戻って再実行。無限ループに注意。 ensure # finally ... end
メソッド全体をtry-catchしたい場合、beginとendは省略可能。
def duke ... rescue => ex # catch ... retry # beginに戻って再実行。無限ループに注意。 ensure # finally ...
例外のスローはraiseキーワードを使う。
rescue修飾子
A rescue Bで、Aが失敗すると、Bが実行される。ミニtry-catchのようなもの。
File.open("duke.txt") rescue "-_-Error" # -_-Error
ブロック
処理のかたまり。
メソッドに何かを実行するブロックを渡すと、前後処理は自動でやってくれるケースが多い。
例えば、以下の場合、ファイルをオープン(前処理)し、その内容を一行ずつ表示する。
ファイルを閉じる処理(後処理)は自動でやってくれる。
File.open("README.md") do |file| file.each_line do |line| print line end end
ブロックの実行
ブロックはメソッドでyieldコマンドで実行する。
yieldコマンドに引数を指定すると、ブロックに渡される。
def m1(q) v = yield(q + 1) puts "value : #{v}" end m1(5) { |n| "wow => #{n}" } # value : wow => 6 m1(7) do |n| # value : haha => 7 "haha => #{n}" end
制御
break, next, redoをブロック内でも使うことができる。
def m1(q) puts "Step1" yield(q) puts "Step2" yield(q + 1) puts "Step3" yield(q + 2) end m1(1) do |q| # Step1 Block Step2 Block Step3 Block => 3!!! if (q == 5) break end puts "Block" "#{q}!!!" end m1(4) do |q| # Step1 Block Step2 => nil if (q == 5) break end puts "Block" "#{q}!!!" end # breakやnextに戻り値を指定できる。 m1(4) do |q| # Step1 Block Step2 => Break! if (q == 5) break "Break!" end puts "Block" "#{q}!!!" end m1(4) do |q| # Step1 Block Step2 Step3 Block => 6!!! if (q == 5) next end puts "Block" "#{q}!!!" end
redoは無限ループの危険がありそうだ。
Proc
ブロックをオブジェクトにしてくれるもの。"ブロックをProcオブジェクトにする"と言い方をするらしい。
Procオブジェクト化したブロックはcallメソッドで呼べる。
def m1(q, &b) # &はブロックをProcオブジェクトに自動変換する。 v = b.call(q) "yaho!#{v}" end m1(5) do |q| # yaho!haha5 "haha#{q}" end myb = Proc.new do |q| "haha2#{q}" end m1(8, &myb) # yaho!haha28 m1(8, myb) # エラー。&をつける必要がある。 def m2(q, b) v = b.call(q) "kaho!#{v}" end myb2 = Proc.new do |q| "kaha2#{q}" end m2(9, myb2) # kaho!kaha29 #別の書き方 : procメソッド myb3 = proc do |q| "kaha3#{q}" end m2(10, myb3) #kaho!kaha310 #別の書き方 : lambda myb4 = lambda do |q| "kaha4#{q}" end m2(11, myb4) #kaho!kaha411 #別の書き方 : -> myb4 = ->(q) { "kaha5#{q}" } m2(12, myb4) #kaho!kaha512 #procとlamdbaの違い1 : lamdbaの方が引数のチェックが厳密だ。 myb5 = proc do |q,a| print [q, a] end myb6 = lambda do |q,a| print [q, a] end myb5.call(2) # [2,nil] myb6.call(2) # エラー : ArgumentError: wrong number of arguments (1 for 2) #procとlamdbaの違い2 : procを作ったメソッド外でproc内でreturnすると、エラーになる。 def m1 proc { return 1 } end def m2 lambda { return 2 } end p = m1 p.call # エラー(procが自分を作ったm1の外で呼びだされ、returnしたため) : LocalJumpError: unexpected return d = m2 d.call # 2
今日はここまで。
webapps配下でないディレクトリにリソースを置く
Tomcatで、ウェブアプリで使われるリソースをwebapps配下でないディレクトリに置きたい場合あります。
例えば、リソース(画像やJSPなど)をアップロードしてウェブアプリの画面を動的に構成したい時です。
またお客様がウェブアプリ本体のソースを修正することなく、カスタマイズできるようにしたい時もありますね。
もし、そういうリソースをwebapps配下におくと、
ウェブアプリをデプロイするたびに既存のリソースが消えてしまうので、困りますね。
こういう場合、Tomcat8に追加されたResources Componentを使えばいいです。
以下のようにserver.xmlのContext要素配下にResources要素とその下のPostResources要素を追加します。
<Context docBase="myweb" path="" reloadable="false"> <Resources allowLinking="false"> <PostResources className="org.apache.catalina.webresources.DirResourceSet" base="${other}/myres" webAppMount="/myres" /> </Resources> </Context>
PostResourcesのbaseにはリソースが位置する絶対パスを指定します。
${other}のようにJVMのシステムプロパティを指定することもできます。
webAppMountにはURLのパス(ウェブアプリのルートパスで次の部分)を指定します。
上記の場合、URLの後ろに/myresと入力した場合、
baseディレクトリにあるリソースを読み込んでレスポンスとして返します。
リソースの位置がwebappsでないだけで、既存webapps配下にあるリソースとまったく同じです。
良い機能ですね。
機械学習の種類とR言語でのパッケージ
機械学習の種類とR言語でのパッケージをざっくりと整理してみました。
自分の理解に役に立つ形態で整理したため、書籍に出るようなまともなものとは違うところがあります。
また、間違った部分もありえますので、気付き次第、修正していくつもりです。
予測
分類(Classification)
データを決まったカテゴリにグループ分けすることです。
kNNアルゴリズム
classパッケージのknn関数
決定木
C5.0アルゴリズムの実装では、C50パッケージのC5.0()関数
回帰(Regression)
数値の予測を行うことです。
線形回帰
statsパッケージのlm(関数)
複数用途
神経網
人間の脳を構成するニューロンの仕組みをコンピューターで真似て予測を行います。
Neuralnetパッケージのneuralnet()関数。
SVM(Support Vector Machine)
kernlabパッケージのksvm()関数。
Apache POIのExcelファイルで日本語セルの列幅を自動調整
Apache POIで列幅を自動で調整してくれる
Sheet#autoSizeColumnメソッドがあります。
数字や英語の場合、ちゃんと列幅を調整してくれるようですが
日本語の場合、Sheet#autoSizeColumnメソッドを呼び出しても、
幅がうまく調整されません。
幅が微妙に足りなかったりします。
こういう場合、セルにフォントを明示的に指定すると、
列幅が問題なく調整されます。
// ...中略... // 日本語での列幅の自動調整のため、フォントを明示的に指定する。 CellStyle cellStyle = workbook.createCellStyle(); Font font = workbook.createFont(); font.setFontName("Serif"); cellStyle.setFont(font); // ... 中略 ... // 列幅を自動調整する。ここでは最初(0番目)の列の幅を自動調整する。 sheet.autoSizeColumn(0, true);
JDKのJavascript(nashron)で外部のJavaクラスを呼び出す方法
自分が作ったクラスや外部のライブラリを呼び出して、
機能を作りたい時があります。
普通にJavaで作ってもいいですが、
コンパイルが必要ですし、
早く作りたいのにJavaの厳格な文法がちょっと面倒です。
ScalaやGroovyなどを使って
軽くスクリプトを作るのもいいですが、
JDKに標準で入っていないから、やはり面倒。
それでJDK(バージョン8)に標準で入っているJavascriptエンジンnashronを
使ってみました。
しかし、nashronはなかなか外部クラスを認識してくれませんでした。
jrunscriptコマンド(またはjjsコマンド)の実行時に
−classpathや-cpにクラスパスをjavaコマンドと同じ方法で指定したのにも関わらず、
いつもClassNotFoundExceptionが発生して困っていました。
色々と試した結果、やっと外部のJavaクラスを認識してくれたので、その方法をメモします。
まず、jrunscriptの実行時に以下のようにクラスパスを指定します。
Linux(Ubuntu)を基準に説明します。
例えば、/dukelab/libに10個のjarファイルがあって、それらをjrunscriptにクラスパスとして通したいなら、以下のように起動します。
jrunscript -cp `echo /dukelab/lib/* | tr ' ' ':'`
ちょっと複雑で、これ以外の方法もあると思いますが、
今のところ、これで行けました。
単純にjrunscript -cp /dukelab/lib/*とすると、うまく行きません。
Linuxのシェルで"/dukelab/lib/*"が式として評価されて、
jrunscript -cp /dukelab/lib/a.jar /dukelab/lib/b.jar... のように
展開されて実行されます。
コマンドプロンプトでは空白文字で引数を分離していますから、
/dukelab/lib/b.jarがスクリプトファイルとして認識され、jrunscriptが実行されます。
当然/dukelab/lib/b.jarはスクリプトと関係ないバイナリのファイルですから、エラーになってしまいます。
それで上記の`echo /dukelab/lib/* | tr ' ' ':'`のように/dukelab/lib/*の展開後に、
trコマンドで空白文字をクラスパスの区切り文字である:に変換する処理を追加しました。
こうすると、実際には
jrunscript -cp /dukelab/lib/a.jar:/dukelab/lib/b.jar...
のようになるので、クラスパスとしてうまく認識できるようになります。
もし、jarファイルでなく、classファイルが置かれているディレクトリなら、もっと簡単です。
例えば、/dukelab/classes配下にJavaクラスがあるなら、
以下のように指定します。
jrunscript -cp /dukelab/classes
クラスパスを複数指定する時は:(コロン。Windowsでは;(セミコロン))で区切って下さい。
これで準備が終わり、Javascriptの話になりますが、
dukelab.js.test1パッケージにあるTestOneクラスと
dukelab.js.test2パッケージにあるTestTwoクラスをJavascriptで呼び出してみます。
2つのクラスはSystem.out.printlnを呼び出すごく単純なクラスなので、内容は割愛します。
var pkgs = new JavaImporter( Packages.dukelab.js.test1, Packages.dukelab.js.test2 ); with(pkgs) { print("TestOne : " + TestOne.getString()); print("TestTwo : " + TestTwo.getInt()); }
実行すると、以下のように表示されます。
TestOne : wow! TestTwo : great!
つまりいうと、Packagesオブジェクトの次に使うJavaクラスの完全修飾名を指定して呼び出すということです。
ただ、いつもPackages.dukelab.js.test1.TestOne.getString()...ように呼び出すのは辛いから
上記のようにwith文を使ってパッケージを省略して使うのがいいでしょう。
with文はJavascriptではスコープが曖昧になってしまうため、使わない方がいいと言われていますが、
JavascriptでJavaクラスを使う時は便宜上、必須ではないかと思います。
ということで少なくともJavaの中のJavascriptでは、with文は当分健在だろうと勝手に思っています。
そのうち、新しい文法ができるかもしれませんが...
最後にJavascriptにおけるJavaクラスの呼出方法をまとめておきます。
// 完全修飾名で呼出し print(Packages.dukelab.js.test1.TestOne.getString()); // with文でパッケージ(一つ)を省略 with (Packages.dukelab.js.test1) { print(TestOne.getString()); } // with文でパッケージ(一つ以上)を省略 with (new JavaImporter(Packages.dukelab.js.test1, Packages.dukelab.js.test2)) { print(TestOne.getString()); print(TestTwo.getInt()); }
Eclipseでマージしたくないファイルへの対処
Eclipse + Git環境で、マージに対するメモです。
マスタブランチからブランチX(Xはブランチの名前)へマージを行った時、
マージしたくないファイルだけと、
マスタブランチとブランチXとの間で、
違いが出てコンフリクトする場合があります。
例えば、環境ファイルの内容に相違な部分がある場合などです。
その時、コンフリクトしたファイルに対して、Team Synchronizing Perspectiveで、
Mark as Mergedし、コンフリクトを解消し、
中身もブランチXのHEAD、つまり元の内容にしても、
依然と米印のアイコンがつきます。
この状態でコミットすると、
コンフリクトしたファイルの中身は変わっていないのに
新しい履歴ができてしまいます。
それでも構わないなら、いいですが、
後で以前のソースを探す時、不便になるのは間違いないです。
これを解消するためには、マージしたファイル全てをコミットする前に、
マージしたくないコンフリクトしたファイルの中身を元に戻した(Replace WithでHEADに戻す)後、
Team > Advanced > Untrackします。
それからコミットが終わると、
該当ファイルに対してTeam > Add to Indexします。
こうすると、マージしたくないファイルへは何の影響を与えず、
マージを終えることができます。
コンフリクトしたファイルの数が多いと、手間かかりますが、
そういう場合は、コンフリクトが多いこと自体を解消した方がいいですね。
ErlangとJavaをつなぐ
この記事では、ErlangとJavaの連携方法を説明します。
使い道
Erlangで出来ているプログラムを使いたいが、今Erlangが分かる人がいない。
でも、Javaが分かる人はいる。こういった状況でErlang + Javaが使えるのではないでしょうか。
また、Erlangがネットワークや並行処理に強い反面、
他の言語に比べてパフォーマンスがよくないところ(演算など)があるようで、
そういった部分はJavaに担当させるのもいいでしょう。
GUIやRDB操作はJavaに任せて、分散処理はErlangに担当させるなどもありだと思います。
実際、Erlang + Javaではありませんが、
ある商用のメール配信エンジン(?)は、
メインをErlangにして、計算速度が必要な部分は
C言語で開発したとの記事を見たことがあります。
Jinterface
JavaからErlang プログラムを呼び出すための、Erlang 公式Java APIパッケージです。
APIは実際通信を行う部分とErlangデータタイプをJavaクラスとして実装した部分で構成されています。
このAPIパッケージを使えば、Erlangプログラムと連携できます。
jinterfaceのjarファイルは、${ERLANG_HOME}/lib/jinterface(又はjinterface-x.y.z)/privディレクトリ配下にOtpErlang.jarという名前で配置されています。
サンプル
受け取ったメッセージをそのまま返すエコサーバのようなErlangプログラムと、
そのエコサーバを呼び出すJavaプログラムを作成してみます。
まず、Erlangプログラムです。
Erlang 基礎ポイント7 - 分散処理 - DukeLabに出たサンプルソースと同じです。
-module(echo). -export([start/0, send/2]). start() -> register(echo, spawn(fun() -> loop() end)). send(Msg, Receiver) -> Receiver ! {self(), {server, Msg}}, receive {client, Res} -> Res end. loop() -> receive {From, {server, Msg}} -> From ! {client, string:concat("Echo response : ", Msg)}, loop() end.
このErlangプログラムをコンパイルして、実行しておきます。
今回は、VirtualBox上に動くUbuntu 12.04で実行しました。
REPL環境上でテストもしてみます。
Javaからアクセスする時、識別に必要なため、erl起動時にnameとsetcookieの指定が必要です。
nameとsetcookieはメモしておいて下さい。
$ erl -name echoserver@vpc1.com -setcookie echocookie (echoserver@vpc1.com)1> c(echo). {ok,echo} (echoserver@vpc1.com)2> echo:start(). true (echoserver@vpc1.com)3> echo:send("Hello!!", echo). % 自分自身への呼出でテスト。 "Echo response : Hello!!"
次は、Javaプログラムです。
ビルドパスにjinterfaceのjarファイル(OtpErlang.jar)を追加して下さい。
今回は、Windows 7環境とEclipseで作成しました。
こちら側のPCにもErlangがインストールされていなければなりません。
jinterfaceのjarだけでは動かないので、注意して下さい。
package dukelab.erlangjavatest; import java.io.IOException; import com.ericsson.otp.erlang.OtpErlangAtom; import com.ericsson.otp.erlang.OtpErlangDecodeException; import com.ericsson.otp.erlang.OtpErlangExit; import com.ericsson.otp.erlang.OtpErlangObject; import com.ericsson.otp.erlang.OtpErlangString; import com.ericsson.otp.erlang.OtpErlangTuple; import com.ericsson.otp.erlang.OtpMbox; import com.ericsson.otp.erlang.OtpNode; public class ErlangJavaTest { public static void main(String[] args) throws IOException, OtpErlangDecodeException, OtpErlangExit { // javanode : Javaプログラム側のホスト名です。任意で指定します。 // echocookie : Erlangプログラム側でerl実行時、指定したクッキー名と同じです。 OtpNode node = new OtpNode("javanode", "echocookie"); OtpMbox mBox = node.createMbox(); // メッセージをErlangプログラム側に送ります。 // これをErlangプログラムで表現すると、 // { echo, 'echoserver@vpc1.com' } ! { self(), {server, "Hello Erlang, I am Java."} }になります。 { OtpErlangTuple tuple = createTuple( mBox.self(), createTuple( new OtpErlangAtom("server"), new OtpErlangString("Hello Erlang, I am Java.") ) ); // echo : Erlangプログラム側で登録したプロセス名です(register(echo, spawn(fun() -> loop() end)))。 // echoserver@vpc1.com : Erlangプログラム側でerl実行時、指定したホスト名です。 mBox.send("echo", "echoserver@vpc1.com", tuple); } // 応答を受け取ります。 { OtpErlangObject result = mBox.receive(); OtpErlangTuple tuple = (OtpErlangTuple) result; OtpErlangAtom atom = (OtpErlangAtom) tuple.elementAt(0); OtpErlangString str = (OtpErlangString) tuple.elementAt(1); System.out.println("Response from Erlang : " + str); } } private static OtpErlangTuple createTuple(OtpErlangObject... msg) { return new OtpErlangTuple(msg); } }
その後、JavaプログラムのPCにあるhostsファイルに、
先ほどのErlang実行時にnameに指定したドメイン名とIPアドレス(Erlangを実行したPC)の対応を追加します。
例えば、以下のようにです。
192.168.56.101 vpc1.com
さあ、Javaプログラムを実行してみましょう。
Response from Erlang : "Echo response : Hello Erlang, I am Java."
できました!
整理
jinterfaceを使うと、Erlangプログラムと同じく動作するプログラムを
Javaで作成することができます。
サーバ役割のプログラムもクライアント役割のプログラムもできます。
いくつかのErlang機能に対応するJavaクラスを以下に並べます。
- Erlang起動(Erlangの仮想マシン) : OtpNode
- メッセージをやりとりする(Erlangでの!やreceiveなど) : OtpMbox
- タプル : OtpErlangTuple
- 文字列 : OtpErlangString
- アトム : OtpErlangAtom
この記事が理解できたら、後は、参考資料を読みながら、掘り下げていけばいいと思います。