ジョギング
- 香椎浜 x 2 周
- 最近は 29 分くらい (6.5 キロ位) なので, 朝からだとまあまあ早いペースかも
日課
- (腕立て x 50 + 腹筋 x 50) x 3
夕飯
- 奥さんが体調イマイチだというので, うどんを作る
今日のるびぃ ~ exercism.io で世界を相手に Ruby のプログラム問題を解いていく (2) ~
exercism.io というプログラム問題ライブラリで提供されている Ruby の問題を解いていきたいと思います.
今日の問題 ~ Calculate the Hamming difference between two DNA strands. ~
Calculate the Hamming difference between two DNA strands.
2 つの塩基配列の Hamming differnce を計算しろってことらしいんだが, そもそも Hamming differnce って何?ってところからのスタートなのでかなり戸惑った...
It is found by comparing two DNA strands and counting how many of the nucleotides are different from their equivalent in the other string. GAGCCTACTAACGGGAT CATCGTAATGACGGCCT ^ ^ ^ ^ ^ ^^
おそらく, 2 つの塩基配列を比較して, 各ヌクレオチドの違いの数を計算しろってことなんだろう...ということで, 問題を解いていく.
テスト
以下のようなテストが用意されている.
require 'minitest/autorun' require_relative 'hamming' # Common test data version: 2.0.1 f79dfd7 class HammingTest < Minitest::Test def test_empty_strands # skip assert_equal 0, Hamming.compute('', '') end ... def test_large_distance_in_off_by_one_strand # skip assert_equal 9, Hamming.compute('GGACGGATTCTG', 'AGGACGGATTCT') end def test_disallow_first_strand_longer # skip assert_raises(ArgumentError) { Hamming.compute('AATG', 'AAA') } end
実装
現在の自分の Ruby 力だと, 以下が精一杯.
class Hamming def self.compute(a1, a2) raise ArgumentError if a1.size != a2.size array1 = a1.split('') array2 = a2.split('') diff_flag = [] array1.each_with_index do |v, i| if v == array2[i.to_i] diff_flag << 0 else diff_flag << 1 end end return diff_flag.count(1) end end module BookKeeping VERSION = 3 end
以下のような動きになる.
- Hamming.compute クラスメソッドの引数は同じ文字列数が必須 (同じで無い場合, AregumentError で例外)
- 引数を配列化する
array1
の each_with_index で回して, インデックス番号を利用してarray2
の要素を取り出していく- 3 で取り出した要素を
array1
の要素と比較して,diff_flag
配列に0
(一致していた場合),1
(不一致だった場合) を append していく - 最後に
diff_flag
で不一致となった場合の要素1
の数をカウントする
テストを走らせてみる.
$ ruby hamming_test.rb Run options: --seed 50416 # Running: ................ Finished in 0.001120s, 14281.6851 runs/s, 14281.6851 assertions/s. 16 runs, 16 assertions, 0 failures, 0 errors, 0 skips
LGTM.
publish
publish すると, 自動的に以下のようなコメントが付いた.
Whenever you are looping through a collection and find yourself writing a conditional (if or unless) nested inside of the loop, take a moment to look through the available enumerable methods. There are some very handy ones that might let you simplify.
どうやら, もっと良いソリューションがあるようだ.
写経
他の挑戦者のコードをざーっと見ていて, 以下のような書き方が一番美しく見えたので写経.
class Hamming def self.compute(a1, a2) raise ArgumentError if a1.size != a2.size a1.chars.zip(a2.chars).count { |x, y| x != y } end end module BookKeeping VERSION = 3 end
- String#chars で文字列を文字で分割して配列で返す
- 配列を Array#zip でマージした上で, ブロック内で配列の要素を比較し, そのブロック内の結果を count メソッドでカウントしている
一度, 配列にした上で要素を比較していくというアプローチは自分のコードと同じであるが, こちらの方が超シンプルで美しい.
exercism.io って
世界中の人の書き方が学べてイイ感じ.