1. Qiita
  2. 投稿
  3. Ruby

ruby でこう書くのは、python ならこう書く、のメモ

  • 11
    いいね
  • 0
    コメント

ruby に慣れていて python に慣れていないんだけど、python を書く機会が増えてきたので備忘録のような感じで。

python は完全に初心者。
python 3。python 2.x のことは気にしないことにした。

長さ

ruby
ary_len = [1,2,3].size # [1,2,3].length でもいい
hash_len = {a:1}.size # {a:1}.length でもいい
string_len = "hoge".size # "hoge".length でもいい

range_len = (1..9).size # Range#length はない。
python3
ary_len = len([1,2,3])
dic_len = len({"a":1})
string_len = len("hoge")
range_len = len(range(1,10)) # 1〜9

まあこの辺りは簡単。

Object の周辺

ruby
[].class #=> Array
1.class #=> Integer
[].is_a?(Enumerable) #=> true
Enumerable===[] #=> true
Enumerable==="" #=> false
[1,1.0,1r,1i].map{ |x| x.is_a?( Numeric ) } #=> [true, true, true, true]
python3
type([]) #=> <class 'list'>
type(1) #=> <class 'int'>

ruby の Enumerable かどうかに相当しそうな処理は、以下の通り:

python3
from collections import Iterable
isinstance([], Iterable) #=> True
isinstance("", Iterable) #=> True

※ special thanks to 大樹さん( http://twitter.com/WniKwo/status/838737021719883776 )

ruby の文字列は Enumerable じゃないけど、python の文字列は Iterable なので要注意。

python で ruby の Numeric のようなクラスを使う例は下記:

python3
from numbers import Number
[isinstance(x,Number) for x in [1.0, 1, ""]] #=> [True,True,False]

※ special thanks to 大樹さん( http://twitter.com/WniKwo/status/838742967426809856 )

Number と Iterable。import すると基底クラスの名前にアクセスできるようになるということだろうか。

複製

ruby
copied = [1,2,3].dup
python3
import copy
copied = copy.copy([1,2,3])

python は import が必要。
とはいえ、リストのコピーは以下のイディオムとメソッドが使える:

python3
copied1 = [1,2,3][:] # たぶんこっちが普通。
copied2 = [1,2,3].copy()

dict にも copy メソッドがある:

python3
copied = {1:2}.copy()

※ special thanks to 大樹さん ( http://twitter.com/WniKwo/status/838745054864793600 )

比較

ruby
[]==[] #=> true 普通の比較
[].equal?([]) #=> false 同じオブジェクトを指しているかどうか
python3
[]==[] #=> true 普通の比較
[] is [] #=> false 同じオブジェクトを指しているかどうか

Array の周辺

range から list/array への変換

ruby
(1..10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[*1..10] #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
python3
list(range(1,11)) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

※ special thanks to あんちもん2 さん : http://twitter.com/antimon2/status/838192408873488385

部分を取り出す

ruby
[*10..100][10,3] #=> [20, 21, 22]
[*10..100][10..12] #=> [20, 21, 22]
python3
list(range(10,101))[10:13] #=> [20, 21, 22]

他に書き方はないのかなぁ。

部分の変更

ruby
a=[*1..5]
a[2,2]=9 # a[2,2]=[9] でも同じ。
a # => [1, 2, 9, 5]
python3
a=list(range(1,6))
a[2:4]=[9] # a[2:4]=9 とは書けない
a #=> [1, 2, 9, 5]

ruby は、a[2,2]=9 とか a[2..3]=[9] とか、いろいろ書き方があるけど、python は上記の一種類だけかな。

最後

[1,2,3][-1] #=> 3
[1,2,3].last #=> 3
python3
[1,2,3][-1] #=> 3

python に last メソッドはないみたい。

push / unshift

ruby
a=[1,2,3]
a.push 9
a.unshift 8
a #=> [8,1,2,3,9]
python3
a=[1,2,3]
a.append(9)
a.insert(0,8)
a #=> [8,1,2,3,9]

python には、先頭に追加する専用のメソッドはないみたい。

pop / shift

ruby
a=[1,2,3,4]
b = a.pop
c = a.shift
[ a, b, c ] #=> [[2, 3], 4, 1]
python3
a=[1,2,3,4]
b = a.pop()
c = a.pop(0)
[ a, b, c ] #=> [[2, 3], 4, 1]

python は pop にどこから取ってくるかの引数があって、0 を指定すると shift の動きになる。

map

ruby
[1,2,3].map{ |x| x*2 } #=> [2,4,6]
%w( 1 2 3 ).map(&:to_i) #=> [1,2,3]
python3
[x*2 for x in [1,2,3]] #=> [2,4,6]
list(map(int,["1","2","3"])) #=>[1,2,3]

inject / reduce

[1,2,3].inject(0){ |acc,x| acc+x } #=> 6
[1,2,3].inject(0, &:+) #=> 6
python3
import functools
functools.reduce(lambda x,y:x+y, [1,2,3], 0) #=> 6
functools.reduce(int.__add__, [1,2,3], 0) #=> 6

select

ruby
[1,2,3,4].select{ |x| x.even? } #=> [2, 4]
python3
[x for x in [1,2,3,4] if x%2==0 ] #=>[2, 4]

最大値

ruby
[1,5,13,21].max #=> 21
[1,5,13,21].max_by{ |x| x % 10 } #=> 5
python3
max([1,5,13,21]) #=> 21
max([1,5,13,21],key=lambda x:x%10 ) #=> 5

flatten

ruby
[1,[[2,3],4],5].flatten #=> [1,2,3,4,5]

python に flatten はないらしい。
see http://d.hatena.ne.jp/xef/20121027/p2

非破壊的 sort

ruby
[1,5,13,20].sort_by{ |x| x%10 } #=> [20,1,13,5]
python3
sorted([1,5,13,20], key=lambda x:x%10 )

python の sort は安定。ruby の sort は安定ではない。

乱数

サンプリング

[1,2,3].sample #=> 1 or 2 or 3
python3
import random
random.sample( [1,2,3], k=1 )[0]

0以上1未満の浮動小数点数

ruby
rand
python3
import random
random.random()

0以上10未満の整数

ruby
rand(10)

あるいは

ruby
rng=Random.new
rng.rand(10)
rng.rand(0..9)
rng.rand(0...10)
python3
import random
random.randint(0,9)

python の範囲指定は両端含む。

未分類

条件演算

ruby
cond=true
val = cond ? "iftrue" : "iffalse"
python3
cond=True
val = "iftrue" if cond else "iffalse"

python の条件演算は、いまのところ全然慣れられそうにない。

combination

ruby
[1,2,3].combination(2).to_a #=> [[1, 2], [1, 3], [2, 3]]
python3
import itertools
list(itertools.combinations([1,2,3],2)) #=> [(1, 2), (1, 3), (2, 3)]

python は複数形。タプルになるところがポイント。
permutations もある。

最後に

加筆予定。
もっと良い書き方があるよ! という意見募集。