Underscore.jsおさらい2(Collections)
※サンプルソースは本家ドキュメントから拝借。分かり辛いものだけ加筆・修正。
each _.each(list, iteratee, [context])
いわゆるforEach。
配列の場合はiterateeの引数に(element, index, list)が、オブジェクトの場合は(value, key, list)が使える。
_.each([1, 2, 3], function(element){ alert(element); }); => alert(1)、alert(2)、alert(3) _.each({one: 1, two: 2, three: 3}, function(element, key){ alert(element); }); => alert(1)、alert(2)、alert(3)
map _.map(list, iteratee, [context])
iteratee処理結果の新しい配列ができる。
_.map([1, 2, 3], function(num){ return num * 3; }); => [3, 6, 9] _.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); => [3, 6, 9] _.map([[1, 2], [3, 4]], _.first); => [1, 3]
reduce _.reduce(list, iteratee, [memo], [context])
最後のiterateeの結果が返る。
処理中に値を保持できる変数(memo)が使えるので、最終的な合計値や計算結果を出す、という処理なんかで使う。
[memo]はmemoの初期値。
var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); => 6 var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 10); => 16
reduceRight _.reduceRight(list, iteratee, memo, [context])
reduceを逆順で行う。
var list = [[0, 1], [2, 3], [4, 5]]; var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); => [4, 5, 2, 3, 0, 1]
find _.find(list, predicate, [context])
条件(predicate)に合致する最初の値を返す。合致する値がなければundefined。
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => 2
filter _.filter(list, predicate, [context])
条件(predicate)に合致する全ての要素を配列で返す。合致する値がなければ空配列。
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => [2, 4, 6]
where _.where(list, properties)
条件のオブジェクト(properties)を含む要素を配列で返す。
filterと似ているが条件指定をオブジェクトに変えた感じ。
SQLのwhere(and)条件をオブジェクト指定するイメージ。
var listOfPlays = [ {title: "Cymbeline", author: "Shakespeare", year: 1611}, {title: "Othello", author: "Shakespeare", year: 1604}, {title: "Lupin The 3rd", author: "Monkey Punch", year: 1967}, {title: "The Tempest", author: "Shakespeare", year: 1611} ]; _.where(listOfPlays, {author: "Shakespeare", year: 1611}); => [{title: "Cymbeline", author: "Shakespeare", year: 1611}, {title: "The Tempest", author: "Shakespeare", year: 1611}]
findWhere _.findWhere(list, properties)
find + where。whereの条件に合致する最初の要素を返す。
reject _.reject(list, predicate, [context])
filterの逆バージョン。predicateの条件に合致しない要素を配列で返す。
演算子を逆にしてfilter使う方が分かりやすくね?
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); => [1, 3, 5]
every _.every(list, [predicate], [context])
条件(predicate)に全て合致すればtrue、1つでも異なればfalseを返す。
_.every([true, 1, null, 'yes'], function(element){ return element != null; }); => false
some _.some(list, [predicate], [context])
everyのOR条件版。条件(predicate)に1つでも合致すればtrue、全て異なればfalseを返す。
everも同様だが、predicateを省略すると_.identityが指定されるので「!hoge」の判定となる。
contains _.contains(list, value, [fromIndex])
listにvalueが含まれていればtrueを返す。
formIndexを指定して検索開始位置を指定できる(けど、オブジェクトの場合は保証されないよな多分)。
_.contains([1, 2, 3], 3); => true
invoke _.invoke(list, methodName, *arguments)
listの各要素に対してmethodNameで指定したメソッド(関数)を実行する。
_.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); => [[1, 5, 7], [1, 2, 3]]
pluck _.pluck(list, propertyName)
オブジェクトの配列から、指定したキー(propertyName)の値を取り出した配列を返す。
mapを簡素化した感じ。
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; _.pluck(stooges, 'name'); => ["moe", "larry", "curly"]
max _.max(list, [iteratee], [context])
最大値を持つ要素を返す。listがオブジェクトの配列であればiterateeで判定対象の値を返す。
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; _.max(stooges, function(stooge){ return stooge.age; }); => {name: 'curly', age: 60};
min _.min(list, [iteratee], [context])
最小値を持つ要素を返す。使い方はmaxと同じ。
sortBy _.sortBy(list, iteratee, [context])
iterateeで指定した条件でソートする。
iterateeに関数ではなく文字列を指定すると、該当プロパティがソートキーとなる。
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); }); => [5, 4, 6, 3, 1, 2] var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; _.sortBy(stooges, 'name'); => [{name: 'curly', age: 60}, {name: 'larry', age: 50}, {name: 'moe', age: 40}];
groupBy _.groupBy(list, iteratee, [context])
iterateeで指定した条件をキーにしたオブジェクト(ハッシュ配列)を返す。
iterateeに関数ではなく文字列を指定すると、該当プロパティの値がキーとなる。
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); }); => {1: [1.3], 2: [2.1, 2.4]} _.groupBy(['one', 'two', 'three'], 'length'); => {3: ["one", "two"], 5: ["three"]}
indexBy _.indexBy(list, iteratee, [context])
groupByと似ているが、groupByがキーに対して該当要素を配列で保持するのに対して、indexByは1つしか持たない。
なので一意の項目をキー指定する前提。
もし一意でないキーを指定した場合は、使用される要素は後勝ちになる。
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; _.indexBy(stooges, 'age'); => { "40": {name: 'moe', age: 40}, "50": {name: 'larry', age: 50}, "60": {name: 'curly', age: 60} } var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 40}, {name: 'curly', age: 60}]; _.indexBy(stooges, 'age'); => { "40": {name: 'larry', age: 50}, "60": {name: 'curly', age: 60} }
countBy _.countBy(list, iteratee, [context])
groupByと似ているが、要素自体ではなく要素数を保持したオブジェクトを返す。
_.countBy([1, 2, 3, 4, 5], function(num) { return num % 2 == 0 ? 'even': 'odd'; }); => {odd: 3, even: 2} var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 40}, {name: 'curly', age: 60}]; _.countBy(stooges, 'age'); => { "40": 2, "60": 1 }
shuffle _.shuffle(list)
Fisher-Yates shuffleアルゴリズムでシャッフルされた配列を返す。非破壊的。
_.shuffle([1, 2, 3, 4, 5, 6]); => [4, 1, 6, 3, 5, 2] (当然実行する毎に結果は変わる)
sample _.sample(list, [n])
listからランダムに要素を取り出す。引数nを指定すれば、その数だけ配列で取り出す。
_.sample([1, 2, 3, 4, 5, 6]); => 4 (当然実行する毎に 以下略) _.sample([1, 2, 3, 4, 5, 6], 3); => [1, 6, 2] (当然 以下略)
toArray _.toArray(list)
配列から配列を作る。
意味が分からないのでカンペしたところ、argumentsの処理に使うのが良いらしい。
あとハッシュ配列を配列化してくれる。順番は保証されないと思う。
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); => [2, 3, 4] _.toArray({a:1, b:2, c:3, d:4}); => [1, 2, 3, 4]
size _.size(list)
要素数を返す。配列ではlength使えばいいけど、ハッシュ配列でlengthの代わりに使う感じ。
_.size({one: 1, two: 2, three: 3}); => 3
partition _.partition(array, predicate)
predicateの条件に合う要素と合わない要素に分けた配列を作る。
_.partition([0, 1, 2, 3, 4, 5], function(num){ return num % 2 == 1; }); => [[1, 3, 5], [0, 2, 4]] _.partition({a:1, b:2, c:3, d:4}, function(num){ return num % 2 == 1; }); => [[1, 3], [2, 4]]
collection終わった・・・今日中に全部終わるかな。。。