rubyの配列、ハッシュ、シンボルあたりを整理する備忘録
ハッシュ、シンボル、配列あたりがごちゃごちゃしているので、まとめる。
備忘録です。
配列
シンプルな配列
array = [1,2,3,4,5]
[1, 2, 3, 4, 5]
要素を追加したり、色々なメソッドを使えます。
array.push(10)
[1, 2, 3, 4, 5, 10]
色んなものが配列の要素になれます。
違う種類のものが入っていてもOKです。
array = [1, "a", [1,2], [3, "b"], {name:"bob", age:18}]
[1, "a", [1, 2], [3, "b"], {:name=>"bob", :age=>18}]
要素を取り出してみます
array[2]
[1, 2]
さらに取り出してみます
array[2][1]
2
ハッシュもこの調子でできそうです。
array[4][:name]
"bob"
ハッシュ
hash = { orange: 100, apple: 200, banana:500 }
{:orange=>100, :apple=>200, :banana=>500}
hash = { a1: 100, b: 200, f:500 }
{:a1=>100, :b=>200, :f=>500}
ハッシュの値にハッシュも配列も入れられる
hash = { a: {aa: 110, ab:120, ac:[130, 140, 150, 160] }, b: 200, f:500 }
{:a=>{:aa=>110, :ab=>120, :ac=>[130, 140, 150, 160]}, :b=>200, :f=>500}
取り出すときは配列と同様に順番に指定していく
hash[:a][:ac][2]
150
ちなみにキーにハッシュや配列も入れることができるっぽい。
使う場面は想像できないが
hash = { {a: 120} => 20, [1,2,3] => 30 }
{{:a=>120}=>20, [1, 2, 3]=>30}
hash[[1,2,3]]
30
hash[{:a=>120}]
20
ハッシュのシンボルについて
keyとして使えるものに、シンボルというものがある。
シンボルは:key
のように使う
Fighter = { :Hanma => "Baki", :Hanayama => "Kaoru", :Orochi => "Doppo" } # 次のように宣言しても全く同じ # Fighter = { Hanma:"Baki", Hanayana: "Kaoru", Orochi: "Doppo" }
{:Hanma=>"Baki", :Hanayama=>"Kaoru", :Orochi=>"Doppo"}
取り出すときは、次のようにして使う
Fighter[:Hanma]
"Baki"
keyは文字列も指定できる。
文字列とシンボルが混在していても、問題なく処理される。
文字列とシンボルは別のものとして扱われるので、注意が必要。
# 同じkeyだと上書きされてしまう Underground_Fighter = { :Hanma => "Baki", :Hanayama => "Kaoru", :Orochi => "Doppo" , Hanma: "Jack" }
<main>:1: warning: key :Hanma is duplicated and overwritten on line 1
{:Hanma=>"Jack", :Hanayama=>"Kaoru", :Orochi=>"Doppo"}
Underground_Fighter[:Hanma]
"Jack"
# keyを:Hanmaと"Hanma"でハッシュに入れる Chika_Fighter = { :Hanma => "Baki", :Hanayama => "Kaoru", :Orochi => "Doppo" , "Hanma" => "Yujiro" }
{:Hanma=>"Baki", :Hanayama=>"Kaoru", :Orochi=>"Doppo", "Hanma"=>"Yujiro"}
Chika_Fighter["Hanma"]
"Yujiro"
Chika_Fighter[:Hanma]
"Baki"
rubyで配列、ハッシュに対する処理をするreduceについてのまとめ備忘録
reduceとは
reduceはinjectの別名。
配列やハッシュを次々に処理していくときに使えるやつ。
早速例示して使ってみる。
まず配列について
# 初期値なしで、配列の中身を順に足していく。 [1,2,3,4,5].reduce() {|sum, i| sum + i }
15
# 初期値を設定できる [1,2,3,4,5].reduce(100) {|sum, i| sum + i }
115
# 偶数なら足す # 初期値なし [1,2,3,4,5].reduce() {|sum, i| puts sum if i % 2 == 0 sum + i else sum end}
1
3
3
7
7
パッと書いてみたが、期待する結果じゃない。 これの挙動を確かめる。
①初期値がないので、[sum, i] = [1, 2]になる。
i=2なので、ifはtrueになり、sum+iが実行される。
よって返り値は3
②Z1周目のループが終わって次のループ。
[sum, i] = [3, 3]になる。
i=3なので、ifはfalseになり、sum(=3)が返される。
③3週目のループ
[sum, i] = [3, 4]になる。
i=4なので、ifはtrueになり、sum+i(=3+4=7)が返される。
④4週目のループ
[sum, i] = [7, 5]になる。
i=5なので、ifはfalseになり、sum(=7)が返される。
初期値がないと、こういった期待しない結果が返ってくる罠に遭遇しそう。
なので、初期値はなるべく都度適切なものを入れたほうがよい気がしている。
# 偶数なら足す # 初期値を0とする [1,2,3,4,5].reduce(0) {|sum, i| if i % 2 == 0 sum + i else sum end}
6
# 1行で書く熟練っぽいコードはまだ慣れない… [1,2,3,4,5].reduce(0) {|sum, i|if i % 2 == 0 then sum + i else sum end}
6
# 偶数なら足す # 初期値は0とする # elseの処理も書かないと、前回の戻り値がないことになってしまう。 [1,2,3,4,5].reduce(0) {|sum, i| if i % 2 == 0 sum + i end}
NoMethodError: undefined method `+' for nil:NilClass
ハッシュについて
# ハッシュのvalueだけを利用する fruit = { apple: 100, banana: 200, orange: 300, lemon: 400 } fruit.reduce(0) {|sum, (key, value)| sum += value}
1000
# ハッシュのvalueを条件にする # 初期値には空の配列[]を使用する fruit.reduce([]) {|array, (key, value)| array.push(key)}
[:apple, :banana, :orange, :lemon]
# reduceは毎回返り値を持たせないとエラーになる罠がある。 fruit.reduce([]) {|array, (key, value)| array.push(key)if value > 250 }
SyntaxError: <main>:1: syntax error, unexpected tIDENTIFIER, expecting '}'
ray.push(key)if value > 250 }
^
# 返り値がないときは、とりあえず何か強引に返しとく # 最後の値が返り値になる #ちゃんと書くならこう fruit.reduce([]) {|array, (key, value)| if value > 250 array.push(key) else array end}
[:orange, :lemon]
# 短く書くならこう fruit.reduce([]) {|array, (key, value)| array.push(key)if value > 250; array}
[:orange, :lemon]
mapよりは若干複雑かな
rubyで配列、ハッシュに対する処理をするmapについてのまとめ備忘録
rubyのmapなどについて使い方をまとめてみます。
map
配列やハッシュの各値に対して同じ操作をしていく。
配列について
# 各値を2倍にする [1,2,3,4,5].map {|i| i*2}
[2, 4, 6, 8, 10]
# 何もしない [1,2,3,4,5].map{|i| i}
[1, 2, 3, 4, 5]
# 全部1にする [1,2,3,4,5].map{|i| 1}
[1, 1, 1, 1, 1]
# 偶数のときだけ2乗にしてみる(失敗) [1,2,3,4,5].map{|i| i**2 if i%2==0}
[nil, 4, nil, 8, nil]
返り値がないとnilが渡される。
# 偶数のときだけ2乗にする [1,2,3,4,5].map{|i| if i % 2 == 0 i ** 2 else i end}
[1, 4, 3, 16, 5]
# 偶数のときだけ2乗にする #1行にまとめる # ※この場合thenを省略するとエラーになる [1,2,3,4,5].map{|i| if i % 2 == 0 then i ** 2 else i end }
[1, 4, 3, 16, 5]
ハッシュについて
ハッシュに対してmapを使っても、返り値がハッシュになるわけではなく、あくまで配列を返す。
これは地味に罠。
# keyを配列にして返す { :name => "hoge", :age => "24"}.map { |key, value| key }
[:name, :age]
# valueを配列にして返す { :name => "hoge", :age => "24"}.map { |key, value| value}
["hoge", "24"]
# keyとvalueを結合した文字列を返す。 { :name => "hoge", :age => "24"}.map { |key, value| "#{key} is #{value}" }
["name is hoge", "age is 24"]
# ちなみにハッシュの書き方はこれでもいい。(というかこれが今は主流…?) { apple: 100, orange: 120, banana: 200, lemon: 250 }
{:apple=>100, :orange=>120, :banana=>200, :lemon=>250}
# valueの条件によってkeyを変更して返してみる。 { apple: 100, orange: 120, banana: 200, lemon: 250 }.map { |key, value| if value > 150 "高い" else "安い" end}
["安い", "安い", "高い", "高い"]
でもこれって、結局ハッシュに対して処理してるならハッシュで返してほしくな〜い?
というのはよくある。気がする。
to_hというのを使うらしい。なるほど〜
# 条件によってvalueを変更してハッシュで返す { apple: 100, orange: 120, banana: 200, lemon: 250 }.map {|key,value| if value > 150 [key, "高い"] else [key, "安い"] end}.to_h
{:apple=>"安い", :orange=>"安い", :banana=>"高い", :lemon=>"高い"}
macのrubyで文字コードcp932でファイルに保存されているか確認する際の落とし穴
まずは元々の挙動を確認
まずは何も指定もせずにファイルに保存するとどうなるのか確認してみます。
say_nice.rb
File.open("nice.txt", "w") do |f| f.puts "nice" end
ファイルの文字コードを確認する方法は
$ nkf --guess filename
または$ file --mime filename
なので、
$ nkf --guess nice.txt
で確認すると、
ASCII (LF)
どうやらASCII (LF)
という文字コードで保存されているらしい。
$ file --mime nice.txt
こちらでも確認してみます。
good.txt: text/plain; charset=us-ascii
ふむ。やはりASCIIみたいですね。
それでは、文字コードをcp932に変更します。 ちなみにcp932というのはShift-JISみたいなやつです。若干違うけどほぼ一緒みたいな認識を勝手にしてます。
say_nice.rb
File.open("nice.txt", "w:cp932") do |f| f.puts "nice" end
これで文字コードはcp932になっているはずですね、確認してみましょう。
$ nkf --guess nice.txt
ASCII (LF)
ファッ!? 変わってないやんけ!
念のためこちらでも確認。
$ file --mime nice.txt
good.txt: text/plain; charset=us-ascii
おっかしいなー。
思い通りの文字コードで保存されない理由
思い通りの文字コードで保存されない理由は、アルファベットしかないから。です。
上記のコードたちだとアルファベットしか出力してないから、文字コードを判断するに足る情報が少なかったからです。
文字コードというのはhtmlファイルのhead情報みたいにファイルのどこかに保存されているのかなと、勝手に思ってましたが、ファイルの中身を見て判断しているみたいですね。
テキストファイルの文字コードは中身で決まる。らしい。 - Qiita
こちら参考にさせていただきました。
つまり、nice
だけだと、asciiもutf-8もcp932も同じ文字コードで表現できてしまう。ってこと!か
というわけで、再度確認してみる
再度元々の挙動を確認
日本語文字に変更して、
say_nice.rb
File.open("nice.txt", "w") do |f| f.puts "いいね" end
$ nkf --guess nice.txt
UTF-8 (LF)
$ file --mime nice.txt
good.txt: text/plain; charset=utf-8
日本語文字を含めると、UTF-8で保存されているみたいですね。
いよいよ本題、cp932で保存したい。
File.open("nice.txt", "w:cp932") do |f| f.puts "いいね" end
確認してみる。
$ nkf --guess nice.txt
Shift_JIS (LF)
えぇ〜・・・
こちらも
$ file --mime nice.txt
good.txt: text/plain; charset=unknown-8bit
こっちに至ってはunknown言われてるやん。。。
cp932じゃなく、Shift_JISと解釈される問題
$ file --mime nice.txt
の方はさておき、Shift_JIS (LF)
と判別されるのは、同じく、cp932
とShift_JIS (LF)
を判別する文字がなかったためでした。
cp932にあって、Shift_JISにないものを文字に入れて検証。
①
を追加。
File.open("nice.txt", "w:cp932") do |f| f.puts "いいね①" end
これで
$ nkf --guess nice.txt
CP932 (LF)
よっしゃ!
こちらは?
$ file --mime nice.txt
good.txt: text/plain; charset=unknown-8bit
unknownのまま。
もうfile --mime
のことなんか知らないっ
あとで調べてみるか・・・
cp932で保存はできてるんだもんな。
NotebookアプリQuiverのスタイルをCSSでいい感じに変更する。
エンジニア御用達のメモアプリ、Quiver。
オンラインで同期できないことを除けば、今の自分にとって最高のツールです。
メモを見る上で、見やすさはとても重要ですね〜
ということで、QuiverのCSSを変更して、使いやすくしたい。
というか、自分で考えたこのStyleよくない〜?ってのを言いたいだけ (どっかのサイトをベースにしたけど忘れてしまった)
StyleのCSSを設定
Preferance > Styles > Preview
で、CSSを書いていくだけ。
こんな感じでCSSを書き込んでいく。
僕の設定したCSSだとこんな感じになります。
割りと気に入ってます。 CSSのコードは以下です。
body, .editor { font-family: 'Hiragino Kaku Gothic Pro', arial, helvetica, sans-serif; } h1 { border: solid 1px #F89174; border-top: solid 5px #F89174; border-radius: 2px; padding: 5px 5px; color: #000; background-color: #f4f5fb; line-height: 1.3em; font-size: 30px; } h2 { border-left: solid 5px #F89174; border-bottom: solid 3px #DADADA; padding: 10px 10px; color: #333333; background-color: #f4f5fb; line-height: 1.3em; font-size: 22px; } h3 { border-bottom: solid 2px #F89174; padding: 10px 10px; } h4 { border-left: solid 3px #F89174; padding: 3px 8px; }
ちなみに最初の方しばらくはずっとこれを拝借していた。
Quiverのスタイルを変える – IT Nerd Diary
ありがとうございました
ターミナルはFinderやエディタから削除したフォルダを参照し続けてしまう。
$ mkdir dev-trash
$ cd dev-trash
でdev-trash
をルートとして考えてみる。
ルート直下にfoo
ディレクトリと、以下のファイルhello_generator.rb
を作る
file = File.open("foo/generated_hello.txt", "w") file.puts "hello"
このファイルを実行すると、foo
の下にgenerated_hello.txt
ファイルを生成する。
$ ruby hello_generator.rb
ここで、新しいターミナル2を開いて、generated_hello.txt
を確認してみる。
$ cd dev-trash/foo
$ cat generated_hello.txt
すると、以下のようになる。
hello
ここで、Finderもしくはエディタからfoo
を削除する
foo
は削除したにも関わらず、
$ cat generated_hello.txt
とすると、
hello
が表示される。
次にhello_generator.rb
の内容を変更する。
file = File.open("foo/generated_hello.txt", "w") file.puts "goodbye"
そして実行。
$ ruby hello_generator.rb
ターミナル2から、generated_hello.txt
の内容を確認してみると、
goodbye
になっているはずだが・・・
実際は
hello
のまま。
ファイルのハッシュを調べてみる。
ターミナル2にて。
$ md5 generated_hello.txt
MD5 (generated_hello.txt) = c157a79031e1c40f85931829bc5fc552
ターミナル1からも確認する
$ md5 generated_hello.txt
MD5 (generated_hello.txt) = d92a12b93565fce571081b028e361e01
どうやら、ターミナル1とターミナル2が指している同じパスのファイルは、別のもののようだ。
実際、ターミナル1から確認すると、
$ cat generated_hello.txt
goodbye
と正常に生成されている。
つまり、ターミナル2から参照しているファイルは、生成されたファイルとは別のファイルということになる。
$ pwd
などで調べてみても、パスは同じなので同じファイルじゃないのー!?と困惑したけど、どうやらパスというのは絶対的なものではないらしい。
これはターミナル2がゴミ箱に移動したファイル(フォルダ)を参照し続けていたことが原因だった。
ちなみに、ターミナル2から
$ cd ../foo
$ cat generated_hello.txt
とすると、
goodbye
と正常なファイルが参照し直される。
$ rm
コマンドを使用すると、ゴミ箱に行かずに削除されるから、そもそも参照ができないので、ファイルがなければエラー、あれば新しいファイルが自動的に参照されるみたいだ。
flexboxの基本(縦並び、横並び、中央寄せ、左寄せ、右寄せ)
xflexbox、便利です。
何もしないと、以下のように、block要素は縦に並ぶ
See the Pen JWerRv by benzenetarou@gmail.com (@benzenetarou) on CodePen.
親要素にdisplay: flex
を設定すると、子要素が横に並ぶ
See the Pen WpYZRw by benzenetarou@gmail.com (@benzenetarou) on CodePen.
flex-direction: column
を設定すると、再び縦に並ぶ
See the Pen XMyepz by benzenetarou@gmail.com (@benzenetarou) on CodePen.
flex-direction: row
にして、横に並べてから、justify-content: flex-end
を設定すると、右側に詰める。
See the Pen QpJqvE by benzenetarou@gmail.com (@benzenetarou) on CodePen.
justify-content: center
で中央寄せになる。
See the Pen qrQPPJ by benzenetarou@gmail.com (@benzenetarou) on CodePen.
flex-direction: column
でコンテンツを縦に配置してからjustify-content: center
にしても縦並びで中央寄せにはなりません。
jusitify-content: center
はあくまでも、横並びのときに横並びの要素をどう配置するかに使うみたいですね。
縦並びで、中央寄せにしたいときは、flex-direction: column
とalign-items: center
を設定します
See the Pen ryQGvJ by benzenetarou@gmail.com (@benzenetarou) on CodePen.
子要素のうち一つだけ、左寄せにしたいときは、子要素でmargin-right: auto
を設定すると、左側に飛んでいきます。
See the Pen ZemXjv by benzenetarou@gmail.com (@benzenetarou) on CodePen.
flexboxの適用範囲は、display:flex
をしていした要素の子要素までです。
なので、孫要素でもいろいろ位置を指定したかったら、子要素にもdisplay:flex
を設定する必要があります。
See the Pen zZMEXJ by benzenetarou@gmail.com (@benzenetarou) on CodePen.
いろいろ複雑な配置もできる
See the Pen YZRrmz by benzenetarou@gmail.com (@benzenetarou) on CodePen.