exercismをCrystalでやった
exercismってなに
これ.いくつか問題があって,投稿してフィードバックもらえますよみたいなやつ.
色々な言語で問題とテストケースが用意されていてCrystalもあったのでやってみた.
適当にやるとだんだんCrystalに慣れてくるかなという感じで.
リポジトリ
1 Hello World
HelloWorld
クラスを定義して hello
メソッドを定義して引数を指定したときはその名前を利用して Hello, NAME!
,指定されていないときは Hello, World!
とする.
ポイントは
- クラスメソッドは
def self.hello
- デフォルト引数は
name = "World"
という感じ - String Interpolationは "Hello, #{name}" という感じ
2 hamming
ハミング距離求めよってやつ
def self.compute(a, b) a.chars.zip(b.chars).count { |l,r| l!=r } end
で終わりだと思っていたけどこれでは無理.... (ver. 0.20.1)
Crystalではこう
Rubyではこう
http://melpon.org/wandbox/permlink/BqnausztCf9N8nrf
これでハマった.今もよく分からん.
3. Gigasecond
109秒を与えられた Time
に足せば良い.
ポイントは
- TImeクラスに +でSpanクラスを足すことができるということ
- Time:::Span.new(0, 0, 10**9)
4 Rna Transcription
ある文字を別の文字にするやつ.
【Ruby】gsubで複数文字を置換したかった話 | カイトズズキ日記
ここを参考にした.
class RnaComplement CONVERTION_TABLE = { "G" => "C", "C" => "G", "T" => "A", "A" => "U" } def self.of_dna(dna) dna.gsub(/#{CONVERTION_TABLE.keys.join("|")}/, CONVERTION_TABLE) end end
5 Bob
与えられた入力に対して決められた文を返すやつ. case-when
でやっただけ.
6 Raindrop
FizzBuzz的なやつ. このScala のやつでやってみた.
Tuple は {}
こう.
case {i % 3 == 0, i % 5 == 0, i % 7 == 0} when {true, false, false} out = "Pling" when {false, true, false} out = "Plang" when {false, false, true} out = "Plong" end
こんな雰囲気.
7 Leap
うるう年判定. Time
に leap_year?
が生えているのでそれを利用する.
https://crystal-lang.org/api/0.20.3/Time.html#leap_year%3F%28year%29%3ABool-class-method
8 Difference Of Squares
Range
を利用した. to_a
で配列にできるのでよしなにできる. reduce
ではなくて, reduce(0)
にしないと配列が空で渡ってきたときに例外が発生するので注意.
https://crystal-lang.org/api/0.20.3/Enumerable.html#reduce%28memo%2C%26block%29-instance-method
9 Pangram
与えられた文字列中で 'a'~'z' までのアルファベットが少なくとも1回出てくるか判定するやつ.
さっきみたいに Range
使って, all?
使えばよい.
10 Largest Series Product
ウォー,Scalaの sliding
みたいなのほしい.....
ポイントは - slidingみたいなのを実装 - BigIntで処理する - 引数が不正のときは例外を出す
例外で new
を忘れがち
# NG # raise ArgumentError # OK raise ArgumentError.new("hogehoge~")
11 Bracket Push
case-when
になぜかハマった. if-elsif
にしたら何故か通った.謎.
以下は良くて,
https://play.crystal-lang.org/#/r/1ig8
これはダメ
https://play.crystal-lang.org/#/r/1ig6
https://play.crystal-lang.org/#/r/1iga
これもダメ
12 Sieve
エラトステネスのふるいじゃない... まぁいいや
while !num.empty? prime << num.shift num = num.reject { |i| i % prime[prime.size - 1] == 0 } end
13 Roman Numerals
ローマ数字化はここを参考にした.
http://codereview.stackexchange.com/a/7939
モンキーパッチやる.
14 Atbash Cipher
最初普通に変換しただけでやったら結果が微妙に違くてよく読んだら,そのまま出すんじゃなかった.
each_slice
というべんりなやつがあって.べんり.
15 Anagram
next
を覚えた.
https://crystal-lang.org/docs/syntax_and_semantics/next.html
16 React
これは写経する感じでやった.なんかもっと上手く書けそうなきがする.
https://crystal-lang.org/api/0.20.3/Proc.html
17 Acronym
糞ゴミ正規表現でゴリ押しした.どうするのが正解なんだろう...?
str.split(/-|\s|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z])(?=[A-Z])/).map(&.[0].upcase).join
18 Binary
baseを2にして to_i
すれば終わり.
19 Run Length Encoding
ランレングス符号化やるやつ.
エンコーディングはスッとできたけど,
def self.encode(str : String) str.chars.chunks { |c| c }.map { |l, r| next l.to_s if r.size == 1 r.size.to_s + l.to_s }.join end
デコーディングがなんか頑張る感じになってしまった.
def self.decode(encoded_str : String) str = "" cnt = "" encoded_str.chars.each { |i| if i.ascii_number? cnt += i else cnt = "1" if cnt.empty? str += i.to_s * cnt.to_i cnt = "" end } str end
20 Pascals Triangle
パスカルの三角形作るやつ.
引数が不正なときは例外を出すようにする.
21 Forth
割りとダルそうなので例を見ながら写経した.
https://github.com/exercism/xcrystal/blob/master/exercises/forth/src/example.cr
property
マクロは getter
と setter
を提供してくれる.
Char::Reader
っていうべんりなやつもある.
https://crystal-lang.org/api/0.20.3/Char/Reader.html
pop_once
, pop_twice
で使ってる yield
はここらへんの話.
ブロックと Proc | プログラミング言語 Crystal
delegate
マクロで処理を委譲できる
https://crystal-lang.org/api/0.20.0/Class.html#delegate%28%2Amethods%2Ctoobject%29-macro
22 Binary Search Tree
これも例を写経する感じにした. Java, Scala以来のジェネリクス,..
include を利用すると module に定義されたメソッドをインスタンスメソッドとして利用できるようになる.
まとめ
Rubyやんけ〜〜〜〜!!!
次はパフォーマンスとかのあたりを読んでおきたい.
はてなインターンの事前課題をCrystalでやった
さいしょに
この記事はCrystal Advent Calendar 2016 4日目の記事.空いていたので後から参加.
最近Crystalをやっている.そのときに id:shiba_yu36 さんの以下の記事を見て良さそうだったのでCrystalでもやってみた.
リポジトリはこちら.
ファイル操作,日付操作,コレクション操作,エラーハンドリング,テスト周りを触ることができて良かった.
ファイル操作
File - github.com/crystal-lang/crystal
ここ見てやってた. File.read_lines
だけで今回は困ることがなくて良かった.
日付操作
Time - github.com/crystal-lang/crystal
日付操作も今回は,epoch秒を Time
クラスに変換して. 決められたフォーマットで出力するだけで良さそうだったので楽だった.
Time.epoch(123456789).to_s("%Y-%m-%dT%H:%M:%S")
こんな感じでできた.
コレクション操作
Enumerable(T) - github.com/crystal-lang/crystal
ここを参考にしながら,自分のScala実装を見て移植していった感じ.ScalaとCrystalでは同じ動作をするメソッドでも名前が違うのがあるので戸惑ったりした.(filter->select とか) そこらへんはRuby由来な感じ?
他にもScalaみたいな感じで,
logs.map(_.status)
ってやりたいけど, logs.map { |log| log.status }
ってやる感じになって不便.
エラーハンドリング
めっちゃ難しい.自分はGoの返り値でエラー返すやつに慣れているので,そもそも例外機構自体新鮮だった. begin~rescue
で囲む感じで良いのかな.
でもここは囲むのが長い感じがする.Optionalみたいなのないのかな.いい方法知りたい.
例外も自分で定義して返す感じ?
それで呼び出し元でも begin~rescue
する感じなのかな.よくわからん...
そこらへんRubyとか例外機構があるプログラミング言語の資料でも読めば良さそう.
テスト
うーむ. Spec.before
使おうとしたけど失敗したりしたw 普通に使えるハズだけどな...
テストは普通に should eq()
の組み合わせで愚直に比較していった.もっと良いやりかたあるのかな?
describe
もどういう単位で分けていけばいいのか分からん.
あと,公式の言語のテストを見ると,メソッドをどういう感じで利用するのか参考にできて良かった.
感想
namespace
っていうやつ,どんな感じでわければいいのかわからん.Rubyもやってこなかったので... あと,例外処理とテストがこれでいいんだろうかみたいなのがあって,テストはもっとうまくかけそうな気がする...
いろんなトピックを一度に扱えてよかった.
はてなインターン最高.