概要
RubyのArray、PythonのHash (Dictionary) の典型的な操作のまとめ。
Python(Ruby)を学習し始めたばかりのRubyist(Pythonista)用の記事です。
前提条件
- Python 3.5.2
- Ruby 2.3.1
参考情報
- Ruby
- Python
メソッド
初期化
- ruby
h = {"a" => 1, "b" => 2, "c" => 3}
h2 = {a: 1, b: 2, c: 3} # symbol をkeyにする場合
- python
d = {'a': 1, 'b': 2, 'c': 3}
要素の取り出し
- ruby
h['c'] #=> 3
h['d'] #=> nil
d['c'] #=> 3
d['d'] #=> 例外KeyErrorが発生
size
- ruby
h.size #=> 3
- python
len( d ) #=> 3
each
要素に対してループを回す
- ruby
h.each do |key,val|
puts key,val
end
- python
for k,v in d.items():
print(k,v)
keys, values
key,valueのリストを取得する
- ruby
h.keys #=> ["a", "b", "c"]
h.values #=> [1, 2, 3]
- python
- Python3ではdict_keys,dict_valuesオブジェクトが返ってくる
- http://www.atmarkit.co.jp/ait/articles/0902/06/news139.html
- dictionaryへの参照を返しているので、dictionary自体を変更するとkeys自体も変わる
- listが欲しい場合は
list()
を使う。
- Python3ではdict_keys,dict_valuesオブジェクトが返ってくる
keys = d.keys() #=> dict_keys(['b', 'a', 'c'])
values = d.values() #=> dict_values([2, 1, 3])
d['d'] = 4
keys #=> dict_keys(['b', 'd', 'a', 'c'])
values #=> dict_values([2, 4, 1, 3])
list(keys) #=> ['b', 'd', 'a', 'c']
配列から生成
- ruby
-
Array#to_h
を使うのが楽
-
a = [1,2,3,4]
a.map {|x| [x,x+3] }.to_h #=> {1=>4, 2=>5, 3=>6, 4=>7}
- python
- リスト内包表記
a = [1,2,3,4]
{ i:i+3 for i in a } #=> {1: 4, 2: 5, 3: 6, 4: 7}
key,valueのmap
- ruby
- keyやvalueを変換したい場合、mapを使う。map自体はArrayのArrayを返すので、それを
Hash[]
でHashに変換する
- keyやvalueを変換したい場合、mapを使う。map自体はArrayのArrayを返すので、それを
h = {"a" => 1, "b" => 2, "c" => 3}
h.map {|k,v| [k.upcase, -v] } #=> [["A", -1], ["B", -2], ["C", -3]]
h.map {|k,v| [k.upcase, -v] }.to_h #=> {"A"=>-1, "B"=>-2, "C"=>-3}
- python
d = {'a': 1, 'b': 2, 'c': 3}
{ k.upper():-v for k,v in d.items() } #=> {'A': -1, 'B': -2, 'C': -3}
has_key?
- ruby
h = {"a" => 1, "b" => 2, "c" => 3}
h.has_key?("a") #=> true
h.has_key?("d") #=> false
- python
- python2までは
d.has_key('a')
というメソッドも使えたらしい。
- python2までは
d = {'a': 1, 'b': 2, 'c': 3}
'a' in d #=> True
'd' in d #=> False
merge
- ruby
-
Hash#merge
を使う。非破壊的なメソッド。破壊的なメソッドはmerge!
- 同じキーがあった場合、デフォルトでは引数の値が優先される。blockを渡せば指定可能
-
h1 = {"a" => 1, "b" => 2, "c" => 3}
h2 = {"d" => 4, "e" => 5, "f" => 6}
h1.merge(h2)
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6}
- python
-
update
というメソッドがあるが、破壊的な操作...
-
d1 = {"a": 1, "b": 2, "c": 3}
d2 = {"d": 4, "e": 5, "f": 6}
d1.update(d2)
d1
#=> {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
delete
- ruby
h = {"a" => 1, "b" => 2, "c" => 3}
h.delete('a') #=> 1
h #=> {"b"=>2, "c"=>3}
- python
d = {"a": 1, "b": 2, "c": 3}
d.pop('a') #=> 1
d #=> {'b': 2, 'c': 3}
デフォルト値の設定
ヒストグラムをとったりする場合に連想配列を使うケース
- ruby
chars = ["a", "b", "b", "c", "c", "c"]
h = Hash.new(0)
chars.each {|c| h[c] += 1 } # 文字数のカウント
h #=> {"a"=>1, "b"=>2, "c"=>3}
- python
- http://www.lifewithpython.com/2015/05/python-dict-default-value.html を参考に
-
default_dict
を使う方法もある
chars = ["a", "b", "b", "c", "c", "c"]
d = {}
for c in chars:
d[c] = d.get(c,0) + 1 # 値があれば取得し、なければ0を返す
d #=> {'a': 1, 'b': 2, 'c': 3}
from collections import defaultdict
chars = ["a", "b", "b", "c", "c", "c"]
d = defaultdict( lambda: 0 )
for c in chars:
d[c] += 1
d
# => defaultdict(<function __main__.<lambda>>, {'a': 1, 'b': 2, 'c': 3})
配列のindexを作る場合
- ruby
- 注意点
Hash.new( [] )
とするとバグる - https://docs.ruby-lang.org/ja/latest/method/Hash/s/new.html
- 注意点
words = ["a1", "b1", "b2", "c1", "c2", "c3"]
h = Hash.new {|hash,key| hash[key] = [] }
words.each {|w| h[ w[0] ] << w }
h
# => {"a"=>["a1"], "b"=>["b1", "b2"], "c"=>["c1", "c2", "c3"]}
- python
words = ["a1", "b1", "b2", "c1", "c2", "c3"]
d = defaultdict( list )
for w in words:
key = w[0]
d[key].append(w)
d
#=> defaultdict(list, {'a': ['a1'], 'b': ['b1', 'b2'], 'c': ['c1', 'c2', 'c3']})