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終わった・・・今日中に全部終わるかな。。。