2つを交互に書いてるとよくこんがらがるので比較してみた。
JavaScriptはES5相当です。
要素を追加
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]
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]
使い方としては大体同じだけど戻り値が結構違う。
var arr = [1, 2, 3];
arr.push(4);
これは4で配列の長さが返される。
arr = [1, 2, 3]
arr.push(4)
これは[1, 2, 3, 4]でレシーバ自身が返される。時々ハマる。
あとjsのsplice()
はかなり多機能でいろいろ使える。
pop, shift
[1, 2, 3].pop() // 3が返る
[1, 2, 3].shift() // 1が返る
[1, 2, 3].pop # 3が返る
[1, 2, 3].shift # 1が返る
これは使い方も戻り値も大体一緒。
配列の検索
[1, 2, 1, 3].indexOf(1);
// 0
[1, 2, 1, 3].lastIndexOf(1);
// 2
[1, 2, 1, 3].index(1)
# 0
[1, 2, 1, 3].rindex(1)
# 2
見つからない場合はindexOf()
は-1を返す。index()
はnilを返す。
rubyはfind_index()
でもおなじ。
配列に特定の値が含まれるか
[1, 2, 3].indexOf(2) >= 0
// true
[1, 2, 3].include? 2
# true
rubyはindex()
がnil返すのでindex()
でもいいといえばいいけど、せっかくあるのでinclude?
使ったほうが多分いいと思います。
指定位置の要素の取り出し
[1, 2, 3, 4].slice(1, 3);
// [2, 3]
[1, 2, 3, 4].slice(1, -1); // 後ろからの指定も出来る
[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を使うのをよく見る感じ。
指定位置の要素の削除
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]
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は上記に加えて、
arr = [1, 2, 3, 4]
arr.delete(2)
# arr = [1, 3, 4]
みたいにdelete(val)
で直接値を指定して消すのができる。
指定位置の要素の置き換え
var arr = [1, 2, 3, 4];
arr.splice(1, 2, 0, 1);
// arr = [1, 0, 1, 4]
arr = [1, 2, 3, 4]
arr[1, 2] = [0, 1]
# arr = [1, 0, 1, 4]
splice()
相当のメソッドはrubyにないので指定部分を取り出して[]=
で直接入れる。splice()
は結構便利。
配列を空に
var arr = [1, 2, 3];
arr.length = 0;
// arr = []
arr = [1, 2, 3]
arr.clear
# arr = []
jsだとlengthに0を入れるのがいいらしい。arr.splice(0, arr.length);
ってやって全部置換しても空にできる。
配列を複製
var arr1 = [1, 2, 3];
var arr2 = arr.slice(0);
// arr1 = [1, 2, 3], arr2 = [1, 2, 3]
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する。
他の配列と結合
[1, 2].concat([3, 4]);
// [1, 2, 3, 4]
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()
の方が速いって聞いた時もあるけどよくわからない。
ソートする
[2, 1, 4, 3].sort(); // 昇順ソート
// [1, 2, 3, 4]
[2, 1, 4, 3].sort(function(a, b) { return b - a }); // 降順ソート
// [4, 3, 2, 1]
[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的なやつ
[1, 2, 3].forEach(function(el) { console.log(el) });
[1, 2, 3].forEach(function(el, idx) { console.log(el, idx) }); // インデックス付き
[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する。(よく忘れる)
要素それぞれに関数を適用
[1, 2, 3].map(function(el) { return el + 1 });
[1, 2, 3].map {|el| el + 1} # collectでもいい
大体似てるけど、順番に書いてるとjsでreturnを忘れ、rubyでreturnを書いてしまうことがよくある。(俺調べ)
条件をみたす要素を取り出す
[0, -2, 1].filter(fuction(el) { return el >= 0 });
[0, -2, 1].select {|el| el >= 0}
名前以外はほぼ一緒。
条件をみたす要素があるか
[0, -2, 1].some(fuction(el) { return el < 0 });
[0, -2, 1].any? {|el| el < 0}
名前以外は(ry
すべての要素が条件をみたすか
[0, -2, 1].every(function(el) { return el < 0 });
[0, -2, 1].all? {|el| el < 0}
名前(ry
隣り合う要素に順番に関数を適用
[1, 2, 3].reduce(function(p, c) { return p + c });
[1, 2, 3].reduce(function(p, c) { return p + c }, 10); // 初期値として10
[1, 2, 3].reduce {|p, c| p + c} # injectでもいい
[1, 2, 3].reduce(10) {|p, c| p + c} # 初期値として10
初期値の与え方がちょっと違うけど、基本的には大体一緒。
ユニークな要素のみ取り出し
[1, 2, 2, 3, 3].filter(function(val, idx, arr) {
return arr.indexOf(val) === idx;
});
// [1, 2, 3]
[1, 2, 2, 3, 3].uniq
# [1, 2, 3]
rubyはそのままのメソッドがある。
jsはfilter()
とindexOf()
で書ける。
二次元配列っぽいのとかを一次元にする
[[0, 1], [2, 3], [4, 5]].reduce(function(p, c) {
return p.concat(c);
});
// [0, 1, 2, 3, 4, 5]
[[0, 1], [2, 3], [4, 5]].flatten
# [0, 1, 2, 3, 4, 5]
jsはreduceとconcatで書ける。