rubyとpythonの配列操作の対応まとめ

# 概要

RubyのArray、Pythonのlistの典型的な操作のまとめ。

Python(Ruby)を学習し始めたばかりのRubyist(Pythonista)用の記事です。

参考 : C++版はこちら [Ruby-C++ 配列操作の対応まとめ](http://qiita.com/yohm13/items/60bd7959ca9c2ff58224)

# 前提条件

- Python 3.5.1
- Ruby 2.2.4

## 参考情報

- Ruby
    - http://docs.ruby-lang.org/ja/2.2.0/class/Enumerable.html
- Python
    - http://docs.python.jp/3.5/tutorial/introduction.html#lists
    - http://docs.python.jp/3.5/tutorial/datastructures.html#more-on-lists
    - http://kesin.hatenablog.com/entry/2013/05/12/004541
    - http://www.walbrix.com/jp/blog/2014-01-findfirst-in-scala-and-python.html

# メソッド

## size

- ruby

```rb
[1,2,3].size   #=> 3
```

- python

```py3
len( [1,2,3] )   #=> 3
```

## each

要素に対してループを回す

- ruby

```rb
[1,2,3,4,5].each do |x|
  puts 2*x    #=> 2,4,6,8,10
end
```

- python

```py3
for x in [1,2,3,4,5]:
    print(2*x)
```

## each_with_index


indexと一緒にループを回す

- ruby

```rb
[5,4,3,2,1].each_with_index do |x,idx|
  print "#{idx}:#{x}, "
end
# => 0:5, 1:4, 2:3, 3:2, 4:1,
```

- python

```py3
for idx,x in enumerate( [5,4,3,2,1] ):
    print("{0}:{1}, ".format(idx,x), end="")
```

## +

配列の結合

- ruby
  - `concat` だと破壊的な操作, `+`だと非破壊的操作

```rb
[1,2,3] + [4,5]     # [1,2,3,4,5]
```

- python
  - `extend` だと破壊的操作。`+`だと非破壊的操作

```py3
[1,2,3] + [4,5]
```

## push (<<)

末尾に要素を追加

- ruby

```rb
a = [1,2]
a << 3
# a => [1,2,3]
```

- python

```py3
a = [1,2]
a.append(3)
# a => [1,2,3]
```

## map

- ruby

```rb
[1,2,3].map {|x| 2*x }  #=> [2,4,6]
```

- python
    - `map`関数を使ってもよいが、リスト内包表記がモダンらしい。

```py3
[ 2*x for x in [1,2,3] ]                 # => [2,4,6]
list( map( lambda x: 2*x, [1,2,3] ) )    # => [2,4,6]
```

## find

- ruby
  - 要素が見つからない場合はnilが返る

```rb
[7,8,9,10,11].find {|x| x%5 == 0 }  #=> 10
```

- python
    - あまり良い記法がみつからない

```py3
[ x for x in [7,8,9,10,11] if x % 5 == 0 ][0]   #=> 10
```

- 追記: http://stackoverflow.com/questions/9868653/find-first-list-item-that-matches-criteria
    - 第二引数はデフォルト値

```py3
next((x for x in [7,8,9,10,11] if x % 5 == 0), None)
```


## find_all

- ruby

```rb
[1,2,3,4,5].find_all {|x| x>3 }  #=> [4,5]
```

- python
    - filterかリスト内包表記を使う

```py3
[ x for x in [1,2,3,4,5] if x > 3]     #=> [4,5]
list( filter( lambda x: x>3, [1,2,3,4,5] ) )    #=> [4,5]
```

## sort

- ruby

```rb
[4,1,3,2,5].sort  #=> [1,2,3,4,5]
```

- python

```py3
sorted( [4,1,3,2,5] )   #=> [1,2,3,4,5]
```

## sort_by

- ruby

```rb
[4,1,2,3,5].sort_by {|x| (3-x).abs }  #=> [3,4,2,1,5]
```

- python

```py3
sorted( [4,1,3,2,5], key= lambda x: abs(3-x) )
```

## index

- ruby
    - 該当要素がなければnilが返る

```rb
[5,1,4,2,3].index(2)  #=> 3
```

- python
    - 該当要素がなければ例外が発生

```py3
[5,1,4,2,3].index(2)  #=> 3
```

## all?

- ruby

```rb
[2,4,6,8].all? {|x| x % 2 == 0 }  #=> true
[2,4,6,9].all? {|x| x % 2 == 0 }  #=> false
```

- python

```rb
all( x%2==0 for x in [2,4,6,8] )   #=> True
all( x%2==0 for x in [2,4,6,9] )   #=> False
```

## sum

- ruby
  - injectを使う

```rb
[1,3,5].inject(:+)   #=> 9
```

- python
    - 組み込み関数sumを使う

```py3
sum( [1,3,5] )
```

## inject (reduce)

- ruby

```rb
[1,2,3,4,5].inject(1) {|acc,x| acc*x }   #=> 120
[1,2,3,4,5].inject("") {|acc,x| acc + (x%2==0?'e':'o') }   #=> oeoeo
```

- python
    - reduce関数を使う。Python2までは組み込み関数。Python3からは `functools`をimportする必要がある。

```py3
import functools
functools.reduce( lambda acc,x: acc*x, [1,2,3,4,5], 1 )
functools.reduce( lambda acc,x: acc+("e" if x%2==0 else "o") , [1,2,3,4,5], "" )
```

## uniq

- ruby

```rb
[5,1,1,2,3,5,5].uniq  #=> [5,1,2,3]
```

- python
    - setに入れてからlistに変換する。順番は保存されない。
    - 順番を保存したい場合は、ループを回すしかないようだ。
        - http://www.lifewithpython.com/2013/11/python-remove-duplicates-from-lists.html

```py3
list( set( [5,1,1,2,3,5,5] ) )

li_uniq = []
for x in [5,1,1,2,3,5,5]:
  if x not in li_uniq:
    li_uniq.append(x)
li_uniq    #=> [5,1,2,3]
```

## uniq {block}

- ruby
  - ブロックを評価した結果が重複しているものを削除する

```rb
[4,5,1,2,3,4,5].uniq {|x| x % 3 }   #=> [4,5,3]
```

- python

```py3
li_uniq = []
set_uniq = set()
for x in [4,5,1,2,3,4,5]:
  if x % 3 not in set_uniq:
    li_uniq.append(x)
    set_uniq.add(x%3)
li_uniq                    #=> [4,5,3]
```

## join

- ruby

```rb
[1,5,3,2].join(":")  #=> "1:5:3:2"
```

- python
    - Stringに`join`メソッドがあるというのが非常にわかりづらい。配列は文字列型に明示的に変換しなくてはならない。

```py3
":".join(map(str, [1,5,3,2]))
```

## reverse

- ruby

```rb
[1,2,3].reverse  #=> [3,2,1]
a = [1,2,3]
a.reverse!
a                #=> [3,2,1]
```

- python
    - Listのreverseメソッドは破壊的操作。
    - 非破壊的な操作は組み込み関数の`reversed`を使う。

```py3
list( reversed([1,2,3]) )

a = [1,2,3]
a.reverse()
a                #=> [3,2,1]
```

## group_by

- ruby

```rb
["cat","bat","bear","camel","alpaca"].group_by {|x| x[0]}
# {"c"=>["cat", "camel"], "b"=>["bat", "bear"], "a"=>["alpaca"]}
```

- python
    - ループを回してdictionaryに要素を追加していく

```py3
d = {}
for x in ["cat","bat","bear","camel","alpaca"]:
    key = x[0]
    if key not in d:
        d[key] = []
    d[key].append(x)
d        # => {'c': ['cat', 'camel'], 'a': ['alpaca'], 'b': ['bat', 'bear']}
```

## shuffle

- ruby

```rb
[1,2,3,4,5,6,7].shuffle   #=> [2, 6, 4, 7, 5, 3, 1]
```

- python

```py3
import random
a = [1,2,3,4,5,6,7]
random.shuffle(a)
a                       #=> [4, 5, 6, 2, 7, 1, 3]
```