- 投稿日:2020-08-30T22:36:41+09:00
thorでオプションを定義する6つの方法
Rubyでcliを作るときに定番のgem thorではコマンドのオプション(
--key value
みたいなやつ)を定義するときにmethod_option
を利用する.
しかし,いくつかのブログやドキュメント等を参照すると他にもいくつかの方法がある.
この違いがよくわからなかったのでいろいろ確認した.オプション定義方法を解説する2種類のドキュメント
thorのドキュメントとしては,GitHub wikiと公式webサイトの2種類存在する.
GitHub wikiでは
method_option
とmethod_options
で定義する方法が紹介されている.
こちらのwikiにはoption
/options
を用いて定義する方法については触れられていない.Thor allows you to specify options for its tasks, using method_options to supply a hash of options, or method_option to provide more detail about an individual option.
GitHub/wiki記載のサンプルmethod_option :value, :default => "some value" #=> Creates a string option with a default value of "some value"一方で,公式webサイトでは
Options and Flags
の章にてoption
とoptions
を用いて定義する方法が紹介されている.
こちらのドキュメントにはmethod_option
/method_options
を用いて定義する方法については触れられていない.Thor makes it easy to specify options and flags as metadata about a Thor command:
公式webサイト記載のサンプルclass MyCLI < Thor desc "hello NAME", "say hello to NAME" option :from def hello(name) puts "from: #{options[:from]}" if options[:from] puts "Hello #{name}" end endなお
method_options
とmethod_option
の違いについて GitHub wiki には,
method_option
は個別のオプションに対してより詳細な項目を定義するために利用すると説明がある.
options
とoption
の違いについて公式webサイトには,
options
は複数のoption
を一度に定義できると説明がある.
上記の説明では,method_option
とmethod_options
の関係はoptions
とoption
の関係とは異なるように読める.You can use a shorthand to specify a number of options at once if you just want to specify the type of the options.
また,公式webサイトには上記に加えて
Class Options
の章でclass_option
という別の方法が記載されている.
class_option
はGitHub wikiでは説明はなく,Generators と Groupsで参照されているだけだった.
ただし,公式webサイトでは触れられていないclass_options
も参照されている.You can specify an option that should exist for the entire class by using class_option. Class options take exactly the same parameters as options for individual commands, but apply across all commands for a class.
公式webサイト記載のclass_optionサンプルclass MyCLI < Thor class_option :verbose, :type => :boolean desc "hello NAME", "say hello to NAME" options :from => :required, :yell => :boolean def hello(name) puts "> saying hello" if options[:verbose] output = [] output << "from: #{options[:from]}" if options[:from] output << "Hello #{name}" output = output.join("\n") puts options[:yell] ? output.upcase : output puts "> done saying hello" if options[:verbose] end desc "goodbye", "say goodbye to the world" def goodbye puts "> saying goodbye" if options[:verbose] puts "Goodbye World" puts "> done saying goodbye" if options[:verbose] end end使い分け
method_options と options
この疑問についてはまさに同じ内容のissueが報告されている.
参考: Difference between method_options and options #596結論としてはどちらも同じ.GitHub wikiは内容が古くなっているということ.
実際,GitHub wikiには内容が古くなっているので公式wbサイトを参照してくれと注意書きがあるNOTE: a good part of the documentation here is outdated, see the website instead: http://whatisthor.com
実装を見ても, method_optionsで実装されて options でエイリアスが張られている.
同様に, method_option で実装されて optionでエイリアスが張られてもいる.lib/thor.rb#128alias_method :options, :method_optionslib/thor.rb#165alias_method :option, :method_optionmethod_options と method_option
一方で,
method_options
とmethod_option
(およびoptions
とoption
)の違いについて,
単にmethod_options
は複数のmethod_option
を同時に指定できるというだけでなく,
method_option
でしか定義できない詳細オプションがある様子.
すなわち GitHub wikiが正しい (公式webサイトの記載を自分が読み違えている?).具体的には,
method_options
では:required
,:type
,:default
,:aliases
の4つしか指定できない.
これはmethod_options
を指定したときの処理の実装上,この4つしか対応していないように読める.
その他の指定可能な項目として,公式webサイトでは:desc
,:banner
を,
GitHub wikiでは上記に加えて:lazy_default
,:enum
を,
オプション項目の生成処理の実装を見ると上記に加えて:hide
を
それぞれ指定可能のように見える.method_options と class_options
class_options
およびclass_option
は説明の通り,指定したクラスに定義されたコマンドすべてに適用される.
利用可能な項目はmethod_options
およびmethod_option
と等しい.なお,class_option実装のコメントを見ると
lazy_default
の記載がない.
しかし実際にはclass_option
もmethod_option
も共通の build_optionで生成しているので
おそらくlaze_default
も含めて共通化されている.結論
method_options
とoptions
,method_option
とoption
の機能はそれぞれ同じ.どちらを利用してもよい.method_options
とmethod_option
は役割が異なる.
method_options
は異なる複数のオプションに対して,method_option
は単一のオプションに対して項目を指定する.method_options
はrequired
,type
,default
,aliases
の計4項目を指定できる.method_option
では上記に加えてdesc
,banner
,lazy_default
,enum
,hide
の計9項目を指定できる.method_options
とclass_options
は対象となるコマンドが違うだけで同じ項目を指定できる.class_option
も同様.- ドキュメントは GitHub wikiと公式webサイトがあるが,どちらも古いので両方とも鵜呑みにできない.
- 投稿日:2020-08-30T20:17:09+09:00
ヒトゲノムの配列の特定されてないところを見てみたりする夏休みの絵日記的なやつだよ
はじめに
この記事はすごいテキトーな記事なので真に受けるなよろし。
目的
ヒトゲノム計画では、人のDNAの配列が全部明らかにされたと言われていますが、実際にはわかっていない部分もかなりあるはずです。
どこの部分がわかっていないのか、グラフを描きます。ヒトゲノムのfastaのダウンロード
Gencodeからヒトゲノムの配列がダウンロードできます。
https://www.gencodegenes.org/human/ここでは、贅沢にALLをダウンロードします。
wget ftp://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_35/GRCh38.p13.genome.fa.gz解凍してもいいのですが、
zcat
コマンドを使えばある程度見ることができますね。まずは
head
を表示してみます。zcat GRCh38.p13.genome.fa.gz | head
>chr1 1 NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNはい、早速出てきました。Nの山です。つまり、配列が特定できていない部分がのっけの頭から来ているわけですね。
次に、一応染色体を確認しておきましょう。zcat GRCh38.p13.genome.fa.gz | grep "^>"まあ、こんな感じで大量に出てきます。
次に、本当に配列がTCGANだけの5種類の文字列から構成されているのか確認してみることにします。
きっとコマンドラインツールを使う方法もあると思うのですが、ここはCrystal言語を使って小さなプログラムを書いてしまうことにします。なぜCrystal言語かというと爆速だからですね。count.crcounter = Hash(Char, Int32).new(0) while l = gets l.chomp.each_char do |c| counter[c] += 1 end end p counterはい、Rubyわかる人には何の変哲もないコードですね。ポイントは、Hashの生成時に型を指定しているところだけです。ほかは全部Rubyと同じです。これがCrystalです。ビルドします。
crystal build counter.cr --releaseこのビルド時間を含めると実行速度でJulia等とあまり変わらないかも知れませんが気にしないことにします。
では、TCGANの数を数えてみましょうzcat GRCh38.p13.genome.fa.gz | grep -v "^>" | ./count
grep -v "^>"
で行頭の染色体などを定義している行を省いています。結果は{'N' => 161331703, 'T' => 916993511, 'A' => 914265135, 'C' => 635937481, 'G' => 638590158}となりました。確かに,TCGAおよびN以外の文字列が存在しないことが確認できました。次はNの連続の分布を数えてみましょう。つまりNが何文字連続するか、を調べてみてみることにします。
nseq.crtemp = 0 while l = gets l.chomp.each_char do |c| if c == 'N' temp += 1 elsif temp != 0 puts temp temp = 0 end end end puts temp if temp != 0ビルドします。
crystal build nseq.cr --releaseまずはNの連続する箇所がいくつあるか調べてみましょう。
zcat GRCh38.p13.genome.fa.gz | grep -v "^>" | ./nseq | wc -l1234
そんなに多くないことがわかります。これを長い順に並べて表示するとこんな感じになります。
1っていうのが不思議な気がするのと、100とか50000とかが多いなあといった印象ですかね。
本題
さて、適当に10000文字ごとに、N, AT, CGの割合を計算してくれるようなプログラムを書きます。
n2tcgan = Hash(Char, Int32).new(0) target = ARGV[0] chr = "" loc = 1 flag = false while l = gets if l.starts_with?(">") exit if flag if l == target puts "loc\tN\tAT\tCG" flag = true end next end if flag l.chomp.each_char do |c| tcgan[c] += 1 loc += 1 if loc % 10000 == 0 total = tcgan.values.sum.to_f ta = (tcgan['A'] + tcgan['T']) / total cg = (tcgan['G'] + tcgan['C']) / total n = tcgan['N'] / total puts "#{loc}\t#{n}\t#{ta}\t#{cg}" tcgan = Hash(Char, Int32).new(0) end end end endためしに実行します。
zcat GRCh38.p13.genome.fa.gz | ./n2 ">chr1 1" | headloc N AT CG 10000 1.0 0.0 0.0 20000 0.0001 0.4076 0.5923 30000 0.0 0.4826 0.5174 40000 0.0 0.5288 0.4712 50000 0.0 0.6439 0.3561 60000 0.0 0.6346 0.3654 70000 0.0 0.6669 0.3331 80000 0.0 0.6199 0.3801 90000 0.0 0.6294 0.3706だいたいうまくいってるようですね。Rubyで同じ動作のプログラムを作成すると、実行時間がすごくがかかってしまいますがCrystalは超高速です。これをコマンドラインでuplotに投げていきます。
uplotというのは、UnicodePlots.rbを使ってターミナル上にグラフを表示できる私が個人的に作っているRuby製のツールです。
ここからターミナルにグラフを描いて、それをスクリーンショットを取ってQiitaに貼り付けるというかなり意味のわからないことをしています。
chr1
chr2
chr3
chr4
chr5
chr6
chr7
chr8
chr9
chr10
chr11
chr12
chr13
chr14
chr 15
chr 16
chr 17
chr 18
chr 19
chr 20
chr 21
chr 22
chr X
chr Y
Wikipediaによると、
主にヘテロクロマチン領域が未解読であり、その領域は活性がないそうです。転写とかほとんどされないという意味だと思います。
つまり生物学的にはあまり意味がないということなのかも知れません。しかしこうやってみると、配列のわかっていない部分はずいぶんあるんだな〜という感じですね。
詳しい方とかいらっしゃいましたらご自由に突っ込んでください。
この記事は以上です。
- 投稿日:2020-08-30T18:46:20+09:00
rails AWSのデプロイが反映されない場合
- 投稿日:2020-08-30T18:36:19+09:00
[過去POST]TECH::CAMPのメンターをしていた時の回答メモを一部公開します
過去POST
過去自分がTECH::CAMPのメンターをしていた時期にメモしていた内容を公開します。
小分けにしようとしましたが小粒なものはまとめておきます。
記憶が曖昧なので間違っている箇所もあるかもしれないです…Q.ハッシュの中身が取り出せない
movie = {"title" => "ハリーポッター", "genre" => "ファンタジー", "year" => "2001年"}
から取りたい文字列を取るコードを書きましょう。
のような問題だったと思います。該当コード
def movie_info(movie, data) puts movie[data] end movie = {"title" => "ハリーポッター", "genre" => "ファンタジー", "year" => "2001年"} puts "以下から一つを選んで入力してください。 ・title ・genre ・year" info = gets.chomp movie_info(movie, info)解説
ここで
puts movie[:data]
としてしまうとうまくいかないです。
その原因は型が違うからです。
info = gets.chomp
ここでキーを「文字列」として受け取っているので
ハッシュの定義も文字列"title"を使っているのでここでは問題はおこりません。
puts movie[:data]
一方で、こう記述すると、シンボル型で出力してしまい、
型が違うためなにも出力されません。ちなみに型を調べるのは.classを使うと調べられます。
ex) info.class
もしシンボル型を使いたいなら
movie = {title: => "ハリーポッター”}
のようにハッシュの定義を変えて
info = gets.chomp.to_sym
のように書き換えるとうまくいきます。
puts movie[data.to_sym]
でも大丈夫です。(シンボル型に変換)Q.devise, no method error
devise関連でno method errorが出た時。current_sign_in_atがないなど。
対処方法
deviseによって作成した、該当のマイグレーションファイルを確認
該当箇所周辺のコメントアウト外して
データベースを作成し直す
$ rake db:migrate:reset
このコマンドで一気にできます。このコマンドは、データベースを一度ドロップして、
今あるマイグレートファイルを元にデータベースを作り直すというコマンドです。
もちろんデータベースに入っていたデータは消えます。
色々データが入っていて残しておきたい場合、CSVでデータを出力してどっかに保存してからやるべきかと思います。直前にマイグレートしたものならrollbackで戻っても良いかもしれません。
$ rake db:migrate:status
で現在どのファイルがmigrateされているのか確認できます。
*ちなみに
db:reset
やっても意味ないです。スキーマファイルから作り直すだけなので。原因
deviceをインストールした際、デフォルトでコメントアウトされている項目をそのままにしてしまい
使用したいメソットが生成されなかったため。
もう一度マイグレーションをやり直すことで解決するはず。Q.heroku上で、idが10刻みで付与される
開発環境では問題ないが、本番環境でのみ、変わってしまう。
あまり気になる人はいない気がしますが、これはclearDBのデフォルトの設定です。
herokuでは、dbサーバーとしてcleardbを使っているようです。【参照】
http://w2.cleardb.net/faqs/#general_16
When I use auto_increment keys (or sequences) in my database, they increment by 10 with varying offsets. Why?
ClearDB uses circular replication to provide master-master MySQL support. As such, certain things such as auto_increment keys (or sequences) must be configured in order for one master not to use the same key as the other, in all cases. We do this by configuring MySQL to skip certain keys, and by enforcing MySQL to use a specific offset for each key used. The reason why we use a value of 10 instead of 2 is for future development.
- 投稿日:2020-08-30T18:14:23+09:00
【ruby】splitメソッドで、文字列から配列にしたい。逆も然り。
文字列を配列化させて、配列を文字列にして、、、というパターンの時に、どういう書き方が期待する値になってくれるでしょうか。
ということで、ダメなパターンも交えて、整理していきましょう!
文字列を配列にする
splitメソッド
を使っていきます。split 英訳:分断する
つまり、まとまりのあるもの(文字列等)を分断させて、要素とさせるメソッドになります。(配列化)
引数は、切り取る部分の境目を指定するイメージになります様々なまとまりのパターンから、配列化をしてみました。
させたい配列は、["foo", "bar", "baz"]
とします。さて、どの書き方が合っているでしょうか。
# 配列化 # 返り値 "foo bar baz".split ["foo", "bar", "baz"] # ○ "foo bar baz".split('') ["f", "o", "o", " ", "b", "a", "r", " ", "b", "a", "z"] "foo bar baz".split(',') ["foo bar baz"] "foobarbaz".split ["foobarbaz"] "foobarbaz".split('') ["f", "o", "o", "b", "a", "r", "b", "a", "z"] "foobarbaz".split(',') ["foobarbaz"] "fooxbarxbaz".split('x') ["foo", "bar", "baz"] # ○ "foo, bar, baz".split ["foo,", "bar,", "baz"] "foo, bar, baz".split('') ["f", "o", "o", ",", " ", "b", "a", "r", ",", " ", "b", "a", "z"] "foo, bar, baz".split(',') ["foo", " bar", " baz"] "foo,bar,baz".split ["foo,bar,baz"] "foo,bar,baz".split('') ["f", "o", "o", ",", "b", "a", "r", ",", "b", "a", "z"] "foo,bar,baz".split(',') ["foo", "bar", "baz"] # ○ %w[foo bar baz] ["foo", "bar", "baz"] # ○この中から、期待する配列になる書き方は、4通りということになります。
配列から、文字列にしたい
joinメソッド
を使っていきます。
引数に、要素と要素の間に差し込む値を入れていくイメージになります。# 文字列化 # 返り値 ["foo", "bar", "baz"].join "foobarbaz" ["foo", "bar", "baz"].join('') "foobarbaz" ["foo", "bar", "baz"].join(',') "foo, bar, baz"おまけ 範囲を配列化
# 範囲を配列化 #戻り値 (0..9).to_a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ('a'..'z').to_a ["a",..,"z"] (1..5).map{ |i| i**2 ) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
- 投稿日:2020-08-30T17:21:37+09:00
リスト処理関数(cons,car,cdr,atom,list)実装例まとめ
拙作記事『7行インタプリタ実装まとめ』について,そろそろSchemeとPython以外にも対応しないとなあと思っていろいろ整理した結果,『S式入力の実装部分がほとんどじゃないこれ?』→『あと,リスト処理内容に基準を設けてないと言語ごとに実装方針がバラバラになりそう』となり,とりあえず『
cons
car
cdr
atom
list
が使える』ようにする記述例を先にまとめていくことにした次第.ターゲット言語上での純LISP機能実装に近いとでもいいますか.※Python版については,これを用いたS式入出力記述例も掲載しています(他の言語版も揃ったら別記事に移すかも).
仕様
- ドット対(cons cells)を定義
- アトムは全て文字列,空リストはNULL
cons
car
cdr
を実装- アトムか否かを判定する
atom
を実装- 文字列の羅列から単方向リストを生成する
list
を実装Python(CPython 3.7.3)
ドット対はペア要素のタプルで定義(不変としたいため).空リストNULLは
None
を使用.#### Cons cells are created by using tuple. #### All of atoms are string and the null value is None. def cons(x, y): return (x, y) def car(s): return s[0] def cdr(s): return s[1] def atom(s): return isinstance(s, str) or s == None def list(ts): if not ts: return None else: return cons(ts[0], list(ts[1:]))利用例は次の通り.
def mkassoc(a, b): if a == None or b == None: return None else: return cons(cons(car(a), car(b)), mkassoc(cdr(a), cdr(b))) def assoc(k, vs): if vs == None: return None else: if car(car(vs)) == k: return car(vs) else: return assoc(k, cdr(vs))>>> vs = mkassoc(list(("hoge", "hage", "hige")), list(("10", "20", "30"))) >>> assoc("hage", vs) ('hage', '20') >>> car(assoc("hage", vs)) 'hage' >>> cdr(assoc("hage", vs)) '20'(上記定義を用いたS式入出力記述例)
#### Cons cells are created by using tuple. #### All of atoms are string and the null value is None. def cons(x, y): return (x, y) def car(s): return s[0] def cdr(s): return s[1] def atom(s): return isinstance(s, str) or s == None def list(ts): if not ts: return None else: return cons(ts[0], list(ts[1:])) #### s_read # '(a b c)' # => ['(', 'a', 'b', 'c', ')'] def s_lex(s): return s.replace('(', ' ( ').replace(')', ' ) ').split() # ['(', 'a', 'b', 'c', ')'] # => ('a', 'b', 'c') def s_syn(s): t = s.pop(0) if t == '(': r = [] while s[0] != ')': r.append(s_syn(s)) s.pop(0) return tuple(r) else: if t == 'None': return None else: return t # ('a', 'b', 'c') # => ('a', ('b', ('c', None))) def s_sem(s): if atom(s): return s elif len(s) == 0: return None elif s[0] == '.': return s_sem(s[1]) else: return cons(s_sem(s[0]), s_sem(s[1:])) def s_read(ss): return s_sem(s_syn(s_lex(ss))) #### s_print def s_prcons(s): sa_r = s_print(car(s)) sd = cdr(s) if sd == None: return sa_r elif atom(sd): return sa_r + ' . ' + sd else: return sa_r + ' ' + s_prcons(sd) def s_print(s): if atom(s): return s elif s == None: return None else: return '(' + s_prcons(s) + ')'>>> s_print(s_read('((Apple . 100) (Orange . 120) (Lemmon . 250))')) '((Apple . 100) (Orange . 120) (Lemmon . 250))' >>> x = s_read('((Apple . 100) (Orange . 120) (Lemmon . 250))') >>> car(x) ('Apple', '100') >>> car(car(cdr(x))) 'Orange' >>> s_print(cdr(x)) '((Orange . 120) (Lemmon . 250))'C言語(gcc 8.3.0)
atom
実装のため,まず,文字列とドット対ポインタの両方を扱うことができるnode_t
構造体を定義,それを用いてドット対cons_t
構造体を定義.空リストNULLはNULLポインタを使用.#include <stdio.h> #include <stdlib.h> /* Cons cells are created by using typedef struct. */ /* All of atoms are char* and the null value is NULL. */ typedef unsigned int value_t; enum NODE_TAG { NODE_STRG, NODE_CONS }; typedef struct _node_t_ { value_t value; enum NODE_TAG tag; } _node_t, *node_t; node_t node(value_t value, enum NODE_TAG tag) { node_t n = (node_t)malloc(sizeof(_node_t)); n->value = value; n->tag = tag; return (n); } typedef struct _cons_t_ { node_t x; node_t y; } _cons_t, *cons_t; node_t cons(node_t x, node_t y) { cons_t c = (cons_t)malloc(sizeof(_cons_t)); c->x = x; c->y = y; node_t n = node((value_t)c, NODE_CONS); return (n); } #define str_to_node(s) (node((value_t)(s), NODE_STRG)) #define node_to_str(s) ((char *)(s->value)) #define car(s) (((cons_t)(s->value))->x) #define cdr(s) (((cons_t)(s->value))->y) #define atom(s) (s->tag == NODE_STRG) #define MAXSTR 64 node_t list(const char s[][MAXSTR], const int n) { node_t r = str_to_node(NULL); for (int i = n - 1; i >= 0; i--) { r = cons(str_to_node(s[i]), r); } return (r); }利用例は次の通り.
#include <string.h> node_t mkassoc(node_t a, node_t b) { if (node_to_str(a) == NULL || node_to_str(b) == NULL) { return NULL; } else { return cons(cons(car(a), car(b)), mkassoc(cdr(a), cdr(b))); } } node_t assoc(node_t k, node_t vs) { if (node_to_str(vs) == NULL) { return NULL; } else { if (strcmp(node_to_str(car(car(vs))), node_to_str(k)) == 0) { return car(vs); } else { return assoc(k, cdr(vs)); } } } int main(void) { const char s1[][MAXSTR] = { "hoge", "hage", "hige" }; const char s2[][MAXSTR] = { "10", "20", "30" }; node_t vs = mkassoc(list(s1, 3), list(s2, 3)); node_t k = str_to_node("hage"); node_t r = assoc(k, vs); printf("car(assoc(\"hage\", vs)) = %s\n", node_to_str(car(r))); printf("cdr(assoc(\"hage\", vs)) = %s\n", node_to_str(cdr(r))); free(vs); free(k); free(r); return (0); }car(assoc("hage", vs)) = hage cdr(assoc("hage", vs)) = 20Common Lisp(SBCL 1.4.16)
あくまで参考.ドット対はクロージャで実現.オリジナルと区別するため,
s_cons
s_car
s_cdr
s_atom
s_list
の名前で定義.空リストNULLはNIL
を使用.;;;; Cons cells are created by using lambda closure. ;;;; All of atoms are string and the null value is NIL. (defun s_cons (x y) (lambda (f) (funcall f x y))) (defun s_car (c) (funcall c (lambda (x y) x))) (defun s_cdr (c) (funcall c (lambda (x y) y))) (defun s_atom (s) (and (not (functionp s)) (not (equal s NIL)))) (defun s_list (s) (if (null s) NIL (s_cons (car s) (s_list (cdr s)))))利用例は次の通り.
(defun s_mkassoc (a b) (if (or (equal a NIL) (equal b NIL)) NIL (s_cons (s_cons (s_car a) (s_car b)) (s_mkassoc (s_cdr a) (s_cdr b))))) (defun s_assoc (k vs) (if (equal vs NIL) NIL (if (equal (s_car (s_car vs)) k) (s_car vs) (s_assoc k (s_cdr vs)))))* (defparameter vs (s_mkassoc (s_list '("hoge" "hage" "hige")) (s_list '("10" "20" "30")))) VS * (s_assoc "hage" vs) #<CLOSURE (LAMBDA (F) :IN S_CONS) {50F3E645}> * (s_car (s_assoc "hage" vs)) "hage" * (s_cdr (s_assoc "hage" vs)) "20"Ruby(CRuby 2.5.5)
ドット対は二要素の(凍結)配列で定義.空リストNULLは
nil
を使用.#### Cons cells are created by using Array. #### All of atoms are string and the null value is nil. def cons(x, y) [x, y].freeze end def car(s) s[0] end def cdr(s) s[1] end def atom(s) s.is_a?(String) || s == nil end def list(s) s.size == 0 ? nil : cons(s[0], list(s[1..-1])) end利用例は次の通り.
def mkassoc(a, b) if a == nil || b == nil then return nil else return cons(cons(car(a), car(b)), mkassoc(cdr(a), cdr(b))) end end def assoc(k, vs) if vs == nil then return nil else if car(car(vs)) == k then return car(vs) else return assoc(k, cdr(vs)) end end end>> vs = mkassoc(list(["hoge", "hage", "hige"]), list(["10", "20", "30"])) => [["hoge", "10"], [["hage", "20"], [["hige", "30"], nil]]] >> assoc("hage", vs) => ["hage", "20"] >> car(assoc("hage", vs)) => "hage" >> cdr(assoc("hage", vs)) => "20"JavaScript (Node.js 10.21)
ドット対は二要素の(凍結)配列で定義.空リストNULLは
null
を使用.//// Cons cells are created by using Array. //// All of atoms are string and the null value is null. function cons(x, y) { return Object.freeze([x, y]); } function car(s) { return s[0]; } function cdr(s) { return s[1]; } function atom(s) { return typeof s == 'string' || s == null; } function list(s) { return s.length == 0 ? null : cons(s[0], list(s.slice(1))); }利用例は次の通り.
function mkassoc(a, b) { return a == null || b == null ? null : cons(cons(car(a), car(b)), mkassoc(cdr(a), cdr(b))); } function assoc(k, vs) { if (vs == null) { return null; } else { if (car(car(vs)) == k) { return car(vs); } else { return assoc(k, cdr(vs)); } } }> vs = mkassoc(list(["hoge", "hage", "hige"]), list(["10", "20", "30"])) [ [ 'hoge', '10' ], [ [ 'hage', '20' ], [ [Array], null ] ] ] > assoc("hage", vs) [ 'hage', '20' ] > car(assoc("hage", vs)) 'hage' > cdr(assoc("hage", vs)) '20'備考
記事に関する補足
- 参照用を想定していることもあり,エラーチェックもモジュール化もガーベジコレクションもなにそれおいしいの状態.実用のS式パーサとかは既にたくさんあるしなあ.
- 現バージョンの
list
だと,Common Lisp版を含めて『リストのリスト』が作れない…cons
使えばいっか(いいかげん).変更履歴
- 2020-08-31:JavaScriptの実装例を追加
- 2020-08-30:利用例を連想リスト実装に統一
- 2020-08-30:Rubyの実装例を追加
- 2020-08-30:初版公開(Python,C,Common Lisp)
- 投稿日:2020-08-30T17:11:13+09:00
配列の使い方(高卒の備忘録)
はじめに
個人的な配列についてのまとめ。
配列の定義
array = [] array1 = [1, 2, 3, 4, 5] array2 = ["A", "B", "C"] array3 = (1..5).to_a => [1, 2, 3, 4, 5] array4 = ("a".."c").to_a => [a, b, c]配列に要素を追加
array = [1, 2, 3] ## 先頭に追加 array.unshift(10) p array => [10, 1, 2, 3] ## 最後に要素を追加 array << 10 p array => [1, 2, 3, 10] array.push(10) p array => [1, 2, 3, 10] ## 指定した位置に要素の追加 array.insert(2, 5) p array => [1, 2, 5, 3]insertメソッドは指定位置に追加できるため便利。
配列の要素を削除
array = [1, 2, 3, 4, 5] ## 指定した要素の削除 array.delete(4) p array => [1, 2, 3, 5] ## 先頭の要素を削除 array.shift p array => [2, 3, 4, 5] ## 最後の要素を削除 array.pop p array => [1, 2, 3, 4] ## 指定した位置の要素を削除 array.delete_at(2) p array => [1, 2, 4, 5] ## 指定した範囲の要素の削除 array.slice!(1, 3) p array => [1, 5] ## trueの要素のみ削除 array.select! { |n| n % 2 == 0 } p array => [2, 4] ## falseの要素のみ削除 array.reject! { |n| n % 2 == 0 } p array => [1, 3, 5]配列の出力
array = [1, 2, 3, 4, 5, 6, 7] ## 指定した位置の出力 puts array[0] => 1 puts array[5] => 6 ## 指定した範囲の出力 puts array.slice(3, 4).join => 4567 ## trueの最初の要素のみ出力 puts array.find { |n| n % 3 == 0 } => 3 ## trueの最初の要素の位置を出力 puts array.find_index { |n| n % 3 == 0 } => 2 ## trueの要素のみ出力 puts array.select { |n| n % 2 == 0 }.join => 246 ## falseの要素のみ出力 puts array.reject { |n| n % 2 == 0 }.join => 1357 ## false手前の要素を出力 puts array.take_while { |n| n < 5 }.join => 1234 ## false以降の要素を出力 puts array.drop_while { |n| n < 5 }.join => 567終わりに
基本的なことはこれでできると思います。
- 投稿日:2020-08-30T17:11:13+09:00
配列の使い方(個人的な備忘録)
はじめに
個人的な配列についてのまとめ。
配列の定義
array = [] array1 = [1, 2, 3, 4, 5] array2 = ["A", "B", "C"] array3 = (1..5).to_a => [1, 2, 3, 4, 5] array4 = ("a".."c").to_a => [a, b, c]配列に要素を追加
array = [1, 2, 3] ## 先頭に追加 array.unshift(10) p array => [10, 1, 2, 3] ## 最後に要素を追加 array << 10 p array => [1, 2, 3, 10] array.push(10) p array => [1, 2, 3, 10] ## 指定した位置に要素の追加 array.insert(2, 5) p array => [1, 2, 5, 3]insertメソッドは指定位置に追加できるため便利。
配列の要素を削除
array = [1, 2, 3, 4, 5] ## 指定した要素の削除 array.delete(4) p array => [1, 2, 3, 5] ## 先頭の要素を削除 array.shift p array => [2, 3, 4, 5] ## 最後の要素を削除 array.pop p array => [1, 2, 3, 4] ## 指定した位置の要素を削除 array.delete_at(2) p array => [1, 2, 4, 5] ## 指定した範囲の要素の削除 array.slice!(1, 3) p array => [1, 5] ## trueの要素のみ削除 array.select! { |n| n % 2 == 0 } p array => [2, 4] ## falseの要素のみ削除 array.reject! { |n| n % 2 == 0 } p array => [1, 3, 5]配列の出力
array = [1, 2, 3, 4, 5, 6, 7] ## 指定した位置の出力 puts array[0] => 1 puts array[5] => 6 ## 指定した範囲の出力 puts array.slice(3, 4).join => 4567 ## trueの最初の要素のみ出力 puts array.find { |n| n % 3 == 0 } => 3 ## trueの最初の要素の位置を出力 puts array.find_index { |n| n % 3 == 0 } => 2 ## trueの要素のみ出力 puts array.select { |n| n % 2 == 0 }.join => 246 ## falseの要素のみ出力 puts array.reject { |n| n % 2 == 0 }.join => 1357 ## false手前の要素を出力 puts array.take_while { |n| n < 5 }.join => 1234 ## false以降の要素を出力 puts array.drop_while { |n| n < 5 }.join => 567終わりに
基本的なことはこれでできると思います。
- 投稿日:2020-08-30T16:04:44+09:00
Aizu Online Judge
この記事は、Aizu Online Judgeに取り組む中で勉強したこと等を忘れないようにするため、備忘録として作成するもの。
gets(文字列の入力を受け付ける)
name = gets #Taroと入力し、エンター #=>"Taro\n" name = gets.chomp #Taroと入力し、エンター #=>"Taro" number = gets.to_i #1と入力 #=>1getsは文字列
join (配列の連結)
配列を連結して1つの
文字列
として返す[1,2,3].join #"abc" [1,2,3].join(" ") #"a b c" [1,2,3].join("+") #"1+2+3"繰り返し
times
1000.times do puts "Hello World" end
- 投稿日:2020-08-30T15:34:49+09:00
そこらへんにいるフリーターがdevise使ってみた。
どうも、
未経験からエンジニアを目指しているフリーターです。
今回は初心者でも簡単に、
ゼロからユーザー管理機能を作れることで有名なgem
devise
について、
ところどころ解説をはさみながら、
簡単に紹介させてもらいたいと思います。
まず最初はrailsアプリを作りましょう
rails _6.0.0_ new (ご自身の作りたいアプリ名) -d mysql (最後の-dはオプションなのでいらない人はつけなくて大丈夫です)インストールが終わったら、今作成したフォルダに移りましょう
ターミナルを開き以下のコマンドを実行してください
% cd (ご自身が作成したアプリ名)とりあえずデータを入れるためのデータベースを作ります。
ターミナルを開き以下のコマンドを実行してください
% rails db:create次はdeviceのジェムをGemfileにて追加していきます
gem 'devise'Gemfileにて追加したら忘れずに
bundle installをしてください!!
(rails sで起動も!!)続いて、ターミナルを開いた状態で
次のコマンドを打ってくださいrail g devise:installこのコマンドによりdeviceが始動し始めます
個人的な感想としてはこのコマンド打った時が一番気持ちいです笑コントローラーも忘れずに作成します。
% rails g devise:controllers usersこのコマンドはdeviceのユーザー関係のコントローラーを
一気に作成してくれますコレによりuserのマイグレーションファイルが生成されるので
送り出す工程を忘れてはいけません。
rake db:migrateそしてこのコマンドです
rails g devise:viewsdevice関係のviewを全部一気に
作ってくれます!!僕最初コレ知らなくて、
全部自分で書いてしまってました、、、
もうあの経験はしなくていいんだ!
と考えると心が安らぎます。
以上でdevice関連のコマンド紹介は終わりです!
こんなに簡単に誰もがユーザー管理機能作れちゃうなんて、、、
gemの能力恐るべし、、
ユーザー登録機能に、sns認証を入れたい!
という方は
https://developers.facebook.com/
というところにアクセスして
色々と登録した上で、
gem 'omniauth-facebook'というgemを使うと
Facebookでの認証が可能になります!
(他にもやることあります、、)
ぜひこの機会に一度調べてみてはどうでしょう!!
- 投稿日:2020-08-30T12:27:17+09:00
Rubyで高速素因数分解したい (ABC177E)
参考
https://atcoder.jp/contests/abc177/editorial/82
(これを読んでからじゃないと記事が意味不明だと思います)本題
A以下の数がたくさん与えられて、それらを素因数分解したいとき、
エラトステネスの篩を行って、ついでにふるい落とした数を入れておくと、
素因数分解のときに楽cache = {key(その値) => value(keyをふるい落とした最小の素因数) }みたいなcacheを作ると楽だよという話です。
例) 100を素因数分解する場合
cache[100] #=> 2 = 2で割れる cache[100/2] #=> 2 = 2で割れる cache[50/2] #=> 5 = 5で割れる cache[25/5] #=> 5 = 5で割れる #∴ 100 は 2で2回、5で2回割れるこのcacheを作っておけば、素因数分解をO(logN)でできるねという話です。
今回はこれを用いて素因数分解を高速にできるクラスを作ってみたので、
既存のInteger#prime_division との性能比較をしたいと思います。作ったもの
https://github.com/k-karen/ruby-samples/blob/master/sieve/prime_div_with_sieve.rb
ソースコード
# エラトステネスの篩で素数列挙して高速に素因数分解したい! # ref: https://atcoder.jp/contests/abc177/editorial/82 class PrimeDivWithSieve def initialize(n) @sieve = [] # nまでの素数を入れる @min_div = {} # keyの値の最小の素因数を入れる # 他を篩落とし得る素数はsqrtを上限にできる (2..Math.sqrt(n).floor).each do |i| next if @min_div[i] # ここに値が入ってる = ふるい落とされている @sieve << i # ふるい落とされずに来たらそいつは素数 sieve_target = i * i while sieve_target <= n do @min_div[sieve_target] ||= i sieve_target += i end end (Math.sqrt(n).floor.next..n).each do |i| next if @min_div[i] @sieve << i end end # Integer#prime_division と同じ値を返すようにする # https://docs.ruby-lang.org/ja/latest/method/Integer/i/prime_division.html def prime_division(num) return [[num, 1]] if !@min_div[num] # 素数のときすぐ返す return_array = [] # [[a, x], [b, y]] <=> num = a^x * b^y while num > 1 do prime = @min_div[num] # 最小の素因数, nil => numが素数 break return_array.push([num, 1]) if !prime div_total = 0 while num % prime == 0 do num /= prime div_total += 1 end return_array.push([prime, div_total]) end return_array end def prime_list @sieve end end性能比較
(テストコード全文)[https://github.com/k-karen/ruby-samples/blob/master/sieve/bench_prime_division.rb]
N = 1_000_000 times = N/25 # テスト件数 TESTCASES = (1..N).to_a.sample(times) require 'prime' ans1 = [] ans2 = [] Benchmark.bm 10 do |r| r.report 'MyDivsor' do divisor = PrimeDivWithSieve.new(N) TESTCASES.each do |i| ans1.push(divisor.prime_division(i)) end end r.report 'PrimeDiv' do TESTCASES.each do |i| ans2.push(i.prime_division) end end end# times = N/25 (40,000件) # Result # user system total real # MyDivsor 0.875262 0.032392 0.907654 ( 0.926605) # PrimeDiv 0.849263 0.012468 0.861731 ( 0.879886) # times = N/2 (500,000件) # Result # user system total real # MyDivsor 1.659268 0.058786 1.718054 ( 1.758668) # PrimeDiv 10.787444 0.118755 10.906199 ( 11.071594)件数少ないと微妙ですが、件数増えると篩利用してるほうが早そうです。
ABC177E
https://atcoder.jp/contests/abc177/submissions/16390851
これで勝つると思ってsubmitしたんですが、1つTLEがどうしても消えませんでした。
今回は何回割れるかという情報がいらないので、
もう篩作るときにその値が持ってる素因数をメモしておけばいいじゃんということになりました。
例) 100 => [2,5], 99 => [3, 11]https://atcoder.jp/contests/abc177/submissions/16391235
これで通りました。
(今回の高速素因数分解とは違うろじっくなのでおまけ程度にどうぞ)nまでの各値の素因数を計算(with篩)
https://github.com/k-karen/ruby-samples/blob/master/sieve/enum_elments.rb
ソースコード
# 素因数だけをnまで計算する class EnumElements def initialize(n) @sieve = [] @elements = {} (2..n).each do |i| next if @elements[i] @sieve << i @elements[i] = [i] sieve_target = i * 2 while sieve_target <= n do if @elements[sieve_target] @elements[sieve_target].push(i) else @elements[sieve_target] = [i] end sieve_target += i end end end def elements(num) @elements[num] || [] end end
- 投稿日:2020-08-30T11:06:01+09:00
Ruby で解く AtCoder ABC177 D UnionFind
はじめに
AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。今回のお題
AtCoder Beginner Contest D - Friends
Difficulty: 676今回のテーマ、UnionFind
典型問題の B - Union Find - AtCoder の応用です。
Ruby
ruby.rbclass UnionFind def initialize(n) @parents = Array.new(n, -1) end def find(x) @parents[x] < 0 ? x : @parents[x] = find(@parents[x]) end def parents @parents end def union(x, y) x = find(x) y = find(y) return if x == y if @parents[x] > @parents[y] x, y = y, x end @parents[x] += @parents[y] @parents[y] = x end end n, m = gets.split.map(&:to_i) u = UnionFind.new(n) m.times do a, b = gets.split.map(&:to_i) u.union(a - 1, b - 1) end puts -u.parents.minsub.rb@parents = Array.new(n, -1) @parents[x] += @parents[y]配列
@parents
に初期値-1
を代入します。
次に、ペアとなった配列の初期値-1
を加算します。
これを繰り返すことで、ペアの集合の要素数を取得することができます。sub.rb@parents = [-3, 0, -2, 2, 0]
入力例 1
の場合、マイナスの数値を見ますと、3
と2
のグループに分かれることが分かります。
よって出力は、グループの要素が大きい方の3
になります。
Ruby コード長 (Byte) 548 実行時間 (ms) 260 メモリ (KB) 15824 まとめ
- ABC 177 D を解いた
- Ruby に詳しくなった
参照したサイト
AtCoder Beginner Contest 177 参戦記
- 投稿日:2020-08-30T10:51:54+09:00
初投稿
どうも
エンジニア就職を目指している20代です
現在はTechCamp82期生として最終課題に取り組んでいます
就職までの学習を記録します
既存の内容も多く投稿することになると思います
- 投稿日:2020-08-30T10:14:25+09:00
Ruby問題⑦
最終回です。
問題
3つの整数a b cが与えられた場合、bまたはcがaとの差が1で
かつbとcとの数値の差が2以上の場合はTrue。
それ以外はFalse
と出力するメソッドを作りましょう。出力例:
close_far(1, 2, 10) → True
close_far(1, 2, 3) → False
close_far(4, 1, 3) → Trueヒント
返り値を整数に変換する際はabsメソッドを使いましょう。
abs
対象となる数値に対して「abs」メソッドを実行すると絶対値を取得することができます。すなわち正の数の場合はそのままですが負の数の場合は符号を取って正の数にした数値が取得できます。
実際の使い方は次のようになります。
num = 5.abs #=> 5 num = (-5).abs #=> 5
模範回答
def close_far(a,b,c) x = (a-b).abs y = (a-c).abs z = (b-c).abs if x == 1 && z >= 2 puts "True" elsif y == 1 && z >= 2 puts "True" else puts "False" end end
今回、解説はなかったですが、答えを見れば理解ができる内容でした。
a-bなどの差を代入するのがポイントですね。
思いつかなかったです。
これは、正解に行き着きたかった・・・。
- 投稿日:2020-08-30T10:14:25+09:00
if,else問題
問題
3つの整数a b cが与えられた場合、bまたはcがaとの差が1で
かつbとcとの数値の差が2以上の場合はTrue。
それ以外はFalse
と出力するメソッドを作りましょう。出力例:
close_far(1, 2, 10) → True
close_far(1, 2, 3) → False
close_far(4, 1, 3) → Trueヒント
返り値を整数に変換する際はabsメソッドを使いましょう。
abs
対象となる数値に対して「abs」メソッドを実行すると絶対値を取得することができます。すなわち正の数の場合はそのままですが負の数の場合は符号を取って正の数にした数値が取得できます。
実際の使い方は次のようになります。
num = 5.abs #=> 5 num = (-5).abs #=> 5
模範回答
def close_far(a,b,c) x = (a-b).abs y = (a-c).abs z = (b-c).abs if x == 1 && z >= 2 puts "True" elsif y == 1 && z >= 2 puts "True" else puts "False" end end
今回、解説はなかったですが、答えを見れば理解ができる内容でした。
a-bなどの差を代入するのがポイントですね。
思いつかなかったです。
これは、正解に行き着きたかった・・・。
- 投稿日:2020-08-30T10:07:40+09:00
ActiveRecord::NotNullViolation in Deviseエラー
【概要】
1.結論
2.ActiveRecord::NotNullViolationtとは何か
3.なぜActiveRecord::NotNullViolation in Deviseになるのか
4.どのように解決するか
5.補足
1.結論
db/migrate/""""devise_create""""".rbに
記載してある"t.string password(またはpassword_confirmation)"の記載を削除する!
2.ActiveRecord::NotNullViolationtとは何か
この意味は、「DBの規則上、空欄(NULL)にしてはいけない項目がデータで保存されかけましたよ!そんなことしちゃいけませんよ!」という機械からのご指摘です!
3.なぜActiveRecord::NotNullViolation in Deviseになるのか
2.と掛け合わせると、「デバイスでDBの規則上、空欄(NULL)にしてはいけない項目がデータで保存されかけましたよ!コントローラーで保存して登録されたときだよ!」と行っています。
なぜこのようなことになるかというと、gem'devise'がわざわざpasswordを作ってくれたのに、
被せて作ろうとしているのでどっちのpasswordがいいかわからずNULLになったと思われます!gem'devise'というものはpasswordとそれに対するpassword_confirmationを作ってくれるgemです!
なので
db/migrate/""""_devise_create_""""".rbt.string :password null:false"(password_confirmation)をプログラムしてカラムを作成する必要はないんです!
4.どのように解決するか
db/migrate/""""_devise_create_""""".rbt.string password, null:false" (またはpassword_confirmation)と記載されていると思うので削除しましょう!
5.補足
ちなみにgem'devise'にはpasswordに対してもう一つ付け加えれれている機能があります!
それはバリデーションです!
6文字以上にしなければ、入力ができないように制限が既に機能として備わっているので、
model/uservalidates :password, length { minimum: 5 }を記載する必要がなくなります!
- 投稿日:2020-08-30T08:03:23+09:00
クラスの情報を継承したクラスの作り方
内容
複数のクラスに同じメソッドを定義したい場合、それぞれのクラス全てにそのメソッドを定義すると、同じ記述を何度も繰り返す事になってしまいます。
(例1)
クラス1 クラス2 クラス3
メソッドA メソッドA メソッドA
メソッドB メソッドC メソッドD
複数のクラスが同じメソッドを持つときにクラスが増えれば増えるほどコード量が多くなり、管理も難しくなります。これを防ぐためにクラスの継承について学んでいきましょう。クラスの継承とは
あるクラスに定義されたメソッドを、別の新規クラスで利用できるようにした上でクラスを定義することを継承と言います。
クラスの継承には、親クラスと子クラスの関係があります。元となるクラスを親クラス、親クラスのメソッドを引き継ぎ新しく作成するクラスを子クラスと呼びます。
パトカーやトラックの上位概念である「車」のクラスを作り、そこへ共通の特徴を定義しておきます。車の特徴(親クラス)を継承することで、パトカー(子クラス)とトラック(子クラス)に車の特徴を記述する必要がなくなります。結果、パトカーとトラックだけの特徴を書くだけで済む上、それぞれの特徴が分かりやすくなっています。クラスの継承をする際には、クラスを宣言する際に「<」を用いて、以下のように記述します。
class 子クラス名 < 親クラス名 endそれでは、先ほどの車の例を実際にクラスの継承を用いたコードで書いてみます。
まずは親となるクラスを定義します。Carクラス(親クラス)
class Car def speed_up puts "加速します" end def speed_down puts "減速します" end def horn puts "プップー" end end親クラスには、車が持つ共通の動作を定義しています。
次に子クラスをそれぞれ定義します。今回はパトカーとトラックをそれぞれPatrolCar, TruckCarとして定義します。PatrolCarクラス(子クラス)
class PatrolCar < Car # クラスの継承 def siren puts "ピーポーピーポー" end endTruckCarクラス(子クラス)
class TruckCar < Car # クラスの継承 def carry puts "荷物を載せます運びます" end end親クラスに共通のメソッドを定義することで、子クラスのコード量が少なくなり見やすくなっています。また、これは継承を使う大きなメリットですが、親クラスで定義された共通のメソッドを変更するだけで、変更を子クラスへ容易に反映できることが上記のコードから分かります。
最後に
クラスの継承を使うことによって共通のメソッドを繰り返し書くことなくスッキリとしたコードを書けるので皆さん書いてみてください!