JavaScriptとRubyのArrayのメソッドの比較

2つを交互に書いてるとよくこんがらがるので比較してみた。
JavaScriptはES5相当です。

要素を追加
------------------------------------
```js:javascript
var arr = [1, 2, 3];

arr.push(4);
// [1, 2, 3, 4]

arr.unshift(0);
// [0, 1, 2, 3, 4]

arr.splice(2, 0, 9);
// [0, 1, 9, 2, 3, 4]
```

```rb:ruby
arr = [1, 2, 3]

arr.push(4)
# arr << 4 でもいい
# [1, 2, 3, 4]

arr.unshift(0)
# [0, 1, 2, 3, 4]

arr.insert(2, 9)
# [0, 1, 9, 2, 3, 4]
```

使い方としては大体同じだけど戻り値が結構違う。

```js:js
var arr = [1, 2, 3];
arr.push(4);
```
これは4で配列の長さが返される。

```rb:ruby
arr = [1, 2, 3]
arr.push(4)
```
これは[1, 2, 3, 4]でレシーバ自身が返される。時々ハマる。

あとjsの`splice()`はかなり多機能でいろいろ使える。

pop, shift
------------------------------------
```js:js
[1, 2, 3].pop() // 3が返る 
[1, 2, 3].shift() // 1が返る
```

```rb:ruby
[1, 2, 3].pop # 3が返る
[1, 2, 3].shift # 1が返る
```
これは使い方も戻り値も大体一緒。

配列の検索
------------------------------------
```js:js
[1, 2, 1, 3].indexOf(1);
// 0
[1, 2, 1, 3].lastIndexOf(1);
// 2
```

```rb:ruby
[1, 2, 1, 3].index(1)
# 0
[1, 2, 1, 3].rindex(1)
# 2
```
見つからない場合は`indexOf()`は-1を返す。`index()`はnilを返す。
rubyは`find_index()`でもおなじ。

配列に特定の値が含まれるか
------------------------------------
```js:js
[1, 2, 3].indexOf(2) >= 0
// true
```

```rb:ruby
[1, 2, 3].include? 2
# true
```

rubyは`index()`がnil返すので`index()`でもいいといえばいいけど、せっかくあるので`include?`使ったほうが多分いいと思います。

指定位置の要素の取り出し
------------------------------------
```js:js
[1, 2, 3, 4].slice(1, 3);
// [2, 3]
[1, 2, 3, 4].slice(1, -1); // 後ろからの指定も出来る
```

```rb:ruby
[1, 2, 3, 4].slice(1, 2)
# [2, 3]
[1, 2, 3, 4][1..2]
```

見た目は近いけれど、jsは`slice(begin, end)`で始点と終点の指定なのに対して、rubyだと`slice(index, length)`で長さ指定なのでたまに混乱する。
実際はrubyだと[Range](http://docs.ruby-lang.org/ja/2.1.0/class/Range.html)を使うのをよく見る感じ。

指定位置の要素の削除
------------------------------------
```js:js
var arr = [1, 2, 3, 4];
arr.splice(1, 1);
// arr = [1, 3, 4]
arr = [1, 2, 3, 4];
arr.splice(1, 2);
// arr = [1, 4]
```

```rb:ruby
arr = [1, 2, 3, 4]
arr.delete_at(1)
# arr = [1, 3, 4]
arr = [1, 2, 3, 4]
arr[1..2] = []
# arr = [1, 4]
```

jsは`splice()`の引数を省略すれば削除できる。
rubyは一つなら`delete_at()`で削除できる。複数の場合は空の配列を代入して削除できる。あとrubyは上記に加えて、

```rb:ruby
arr = [1, 2, 3, 4]
arr.delete(2)
# arr = [1, 3, 4]
```

みたいに`delete(val)`で直接値を指定して消すのができる。

指定位置の要素の置き換え
------------------------------------
```js:js
var arr = [1, 2, 3, 4];
arr.splice(1, 2, 0, 1);
// arr = [1, 0, 1, 4]
```

```rb:ruby
arr = [1, 2, 3, 4]
arr[1, 2] = [0, 1]
# arr = [1, 0, 1, 4]
```

`splice()`相当のメソッドはrubyにないので指定部分を取り出して`[]=`で直接入れる。`splice()`は結構便利。

配列を空に
------------------------------------
```js:js
var arr = [1, 2, 3];
arr.length = 0;
// arr = []
```

```rb:ruby
arr = [1, 2, 3]
arr.clear
# arr = []
```

jsだとlengthに0を入れるのがいいらしい。`arr.splice(0, arr.length);`ってやって全部置換しても空にできる。

配列を複製
------------------------------------
```js:js
var arr1 = [1, 2, 3];
var arr2 = arr.slice(0);
// arr1 = [1, 2, 3], arr2 = [1, 2, 3]
```

```rb:ruby
arr1 = [1, 2, 3]
arr2 = arr.clone # arr.dupでもできる
# arr1 = [1, 2, 3], arr2 = [1, 2, 3]
```

どっちも浅いコピーになる。深いコピーしたい時はjsだと`JSON.stringify()`してparseである程度できる。rubyは`Marshal.dump()`してloadする。

他の配列と結合
------------------------------------
```js:js
[1, 2].concat([3, 4]);
// [1, 2, 3, 4]
```

```rb:ruby
arr = [1, 2]
arr.concat([3, 4]) # レシーバ自身が変更される(arr = [1, 2, 3, 4])
arr + [3, 4] # レシーバ自身は変更されない(arr = [1, 2])
# [1, 2, 3, 4]
```

rubyだと`concat()`でレシーバ自身が変更される。jsは変更されないで新しい配列を返すので、動作としては`+`で結合した場合に近い感じ。
jsは`Array.prototype.push.apply()`の方が速いって聞いた時もあるけどよくわからない。

ソートする
------------------------------------
```js:js
[2, 1, 4, 3].sort(); // 昇順ソート
// [1, 2, 3, 4]
[2, 1, 4, 3].sort(function(a, b) { return b - a }); // 降順ソート
// [4, 3, 2, 1]
```

```ruby:ruby
[2, 1, 4, 3].sort # 昇順ソート
# [1, 2, 3, 4]
[2, 1, 4, 3].sort {|a, b| b <=> a} # 降順ソート
# [4, 3, 2, 1]
```

比較関数の書き方ががちょっと違う感じで、rubyは基本的に`<=>`演算子を使って書く。
ただjsもrubyも、
a > b のとき 正の数
a == b のとき 0
a < b のとき 負の数
を返すような関数を渡してあげればちゃんと動く。

foreach的なやつ
------------------------------------
```js:js
[1, 2, 3].forEach(function(el) { console.log(el) });
[1, 2, 3].forEach(function(el, idx) { console.log(el, idx) }); // インデックス付き
```

```rb:ruby
[1, 2, 3].each {|el| puts el}
[1, 2, 3].each.with_index {|el, idx| puts el, idx} # インデックス付き
```

functionとブロックの違いなだけで基本的には大体一緒。
jsはこういうの使う時、`function(value, index, array) {}`で要素, インデックス, 元の配列を受け取れる。
rubyはそのままだと要素だけなので、インデックス使いたいときはwith_indexする。（よく忘れる）

要素それぞれに関数を適用
------------------------------------
```js:js
[1, 2, 3].map(function(el) { return el + 1 });
```
```rb:ruby
[1, 2, 3].map {|el| el + 1} # collectでもいい
```

大体似てるけど、順番に書いてるとjsでreturnを忘れ、rubyでreturnを書いてしまうことがよくある。（俺調べ）

条件をみたす要素を取り出す
------------------------------------
```js:js
[0, -2, 1].filter(fuction(el) { return el >= 0 });
```

```rb:ruby
[0, -2, 1].select {|el| el >= 0}
```

名前以外はほぼ一緒。

条件をみたす要素があるか
------------------------------------
```js:js
[0, -2, 1].some(fuction(el) { return el < 0 });
```

```rb:ruby
[0, -2, 1].any? {|el| el < 0}
```

名前以外は(ry

すべての要素が条件をみたすか
------------------------------------
```js:js
[0, -2, 1].every(function(el) { return el < 0 });
```

```rb:ruby
[0, -2, 1].all? {|el| el < 0}
```

名前(ry

隣り合う要素に順番に関数を適用
------------------------------------
```js:js
[1, 2, 3].reduce(function(p, c) { return p + c });
[1, 2, 3].reduce(function(p, c) { return p + c }, 10); // 初期値として10
```

```rb:ruby
[1, 2, 3].reduce {|p, c| p + c} # injectでもいい
[1, 2, 3].reduce(10) {|p, c| p + c} # 初期値として10
```

初期値の与え方がちょっと違うけど、基本的には大体一緒。

ユニークな要素のみ取り出し
-----------------------------------
```js:js
[1, 2, 2, 3, 3].filter(function(val, idx, arr) {
  return arr.indexOf(val) === idx;
});
// [1, 2, 3]
```

```rb:ruby
[1, 2, 2, 3, 3].uniq
# [1, 2, 3]
```

rubyはそのままのメソッドがある。
jsは`filter()`と`indexOf()`で書ける。

二次元配列っぽいのとかを一次元にする
------------------------------------
```js:js
[[0, 1], [2, 3], [4, 5]].reduce(function(p, c) {
  return p.concat(c);
});
// [0, 1, 2, 3, 4, 5]
```

```rb:ruby
[[0, 1], [2, 3], [4, 5]].flatten
# [0, 1, 2, 3, 4, 5]
```

jsはreduceとconcatで書ける。

参考：
[Array - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)
[Rubyリファレンスマニュアル - class Array](http://docs.ruby-lang.org/ja/2.1.0/class/Array.html)