Enumerableクラス(3)
injectメソッド
【抜粋】 inject: function(memo, iterator) { this.each(function(value, index) { memo = iterator(memo, value, index); }); return memo; },
第一引数memoを初期値として、iteratorによりmemoを変更していき、最終的にこれを返却しています。memoは配列やカスタムオブジェクトの他、文字列や数値も設定できます。
【例】 var array = ["one", "two", "three"]; var ret = array.inject(["zero"], function(memo, value, index){ memo.push(value); memo.push(value); return memo; }); alert(ret); //retは配列。"zero,one,one,two,two,three,three"と表示される。
invokeメソッド
【抜粋】 invoke: function(method) { var args = $A(arguments).slice(1); return this.collect(function(value) { return value[method].apply(value, args); }); },
前述collectメソッドが使用されています。collectメソッドはthisの各要素の値を引数の関数で処理し、その結果を配列にまとめて返すものです。collectメソッドへの引数の関数は、各要素の値(この場合オブジェクト)の第一引数methodと同名のメソッドを実行します。apply関数によりinvokeの第二引数以降を、value[method]の引数としています。
【例】 var dog = { sing : function(f, b){return f + "わん" + b;} } var cat = { sing : function(f, b){return f + "にゃー" + b;} } var cock = { sing : function(f, b){return f + "こけこっこー" + b;} } var array = [dog, cat, cock]; var ret = array.invoke("sing", "「", "」"); alert(ret); //retは配列。"「わん」,「にゃー」,「こけこっこー」"と表示される。
maxメソッド
【抜粋】 max: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (value >= (result || value)) result = value; }); return result; },
iteratorの処理結果の値が、それまでの最大値resultよりも大きい場合に、resultと置き換えています。結果として最大値が返却されます。iteratorがnull(undefined)の場合は、第一引数をそのまま返却するPrototype.Kメソッドが使用されます。「value >= (result || value)」は、resultの初期値が未定義(undefined)なので、ループの初回で必ずtrueとなります。
【例】 var array = ["zero", "one", "two", "three"]; var ret = array.max(function(value, index){ return value.length - index; }); alert(ret); //"4"と表示される。"zero"の文字数-0の結果。
minメソッド
【抜粋】 min: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (value <= (result || value)) result = value; }); return result; },
前述maxメソッドの逆ですね。
【例】 var array = ["zero", "one", "two", "three"]; var ret = array.min(function(value, index){ return value.length - index; }); alert(ret); //"1"と表示される。"two"の文字数-2の結果。
pluckメソッド
【抜粋】 pluck: function(property) { var results = []; this.each(function(value, index) { results.push(value[property]); }); return results; },
各要素の値(この場合オブジェクト)について、引数propertyと同名のプロパティを配列に格納して返却しています。
【例】 var array = ["zero", "one", "two", "three"]; var ret = array.pluck("length"); alert(ret); //retは配列。"4,3,3,5"が表示される。
rejectメソッド
【抜粋】 reject: function(iterator) { var results = []; this.each(function(value, index) { if (!iterator(value, index)) results.push(value); }); return results; },
iteratorがfalseを返却した場合、そのときの要素の値すべてを配列に格納して返却します。前述findAllメソッドと逆の機能です。
【例】 var array = ["zero", "one", "two", "three"]; var ret = array.reject(function(value, index){ return (value.length == 3); //lengthが3の場合trueを返却 }); alert(ret); //retは配列。"zero,three"が表示される。
sortByメソッド
【抜粋】 sortBy: function(iterator) { return this.collect(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); },
まず、各要素の値をvalue、iteratorの処理結果をcriteriaという名前のプロパティで持つ、オブジェクトの配列を作成しています。次に、これを既存のsortメソッドでソートしています。ソートは各オブジェクトのcriteriaプロパティを元に行います。*1ソート関数は正数を返却すると隣り合う要素が入れ替わりますので、この場合、昇順ソートになります。最後に前述pluckメソッドを使い、valueプロパティのみを配列に格納して返却しています。
【例】 var array = ["zero", "one", "two", "three"]; var ret = array.sortBy(function(value, index){ return value.length; }); alert(ret); //retは配列。"one,two,zero,three"が表示される。
つまりこれはオブジェクト配列が特定のプロパティでソートできるということです。
以下は2次元配列のソート例です。
var array = [[0, 10], [1, 9], [2, 8], [3, 7]]; var ret = array.sortBy(function(value, index){ return value[1];//2列目でソート }); alert(Object.inspect(ret)); //"[[3, 7], [2, 8], [1, 9], [0, 10]]"と表示される。
以下はHashオブジェクト(連想配列)のソート例です。返却されるのはキーと値が対になっている2次元配列なので、再度Hashに変換する必要があります。(なんだかな・・・)→Hashに変換すると、、eachメソッドやfor inループで処理される順番が崩れる場合があります。具体的にはOperaでキーに自然数がある場合、これが優先的に処理されてしまいます。Hashオブジェクトのソート結果が配列であるのは妥当ということかもしれません。
//注:Operaでキーに自然数が含まれると正常に動作しないです。以下は参考程度に。 var hash = $H({'one':'1', 'two':'02', 'three':'003'}); var ret = hash.sortBy(function(prop, index){ return prop.key; }).inject($H(), function(memo, value, index){ memo[value[0]] = value[1]; return memo; }); alert(Object.inspect(ret)); //"#<Hash:{'one': '1', 'three': '003', 'two': '02'}>"と表示される。
prop.keyをprop.valueにすれば値でのソートになります。また、Number(prop.value)とすれば数値としてソートします。-(Number(prop.value))とすれば数値として降順ソートになります。文字辞書順の降順は簡単には書けなそうです。(sortBy後にreverseしてHashにするしかないような・・・)
修正案
文字列降順にも対応させると便利な気がします。
【参考】修正案 sortBy: function(iterator, isDesc) { return this.collect(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; if(!isDesc){ return a < b ? -1 : a > b ? 1 : 0; }else{ return a > b ? -1 : a < b ? 1 : 0; } }).pluck('value'); },
第二引数にtrueを設定すると降順になります。
toArrayメソッド
【抜粋】 toArray: function() { return this.collect(Prototype.K); },
各要素の値を配列に格納して返却します。後述のHashオブジェクトをArrayオブジェクトに変換する場合や、Arrayクラスオブジェクトの複製を作成するのに有効です。
var hash = $H({zero:"零",one:"壱",two:"弐",three:"参"}); var array = hash.toArray(); alert(array[2][0]); //"two"と表示される alert(array[2][1]); //"弐"と表示される alert(array.two);//"undefined"と表示される
*1:余談ですが、このソート用関数の作成方法は有用だと思います。2次元配列を特定のカラムでソートすることも可能になります。