batteries/lib/array-ext.js
2010-11-21 20:06:10 -08:00

126 lines
3.1 KiB
JavaScript

exports.extendNative = function() {
Object.keys(ArrayExt).forEach(function(k) {
if (Array.prototype[k]) return; // don't overwrite existing members
Array.prototype[k] = function() {
var fn = ArrayExt[k]
, args = [].slice.call(arguments)
;
args.shift(this);
fn.apply(ArrayExt, args);
};
});
};
var ArrayToString = [].toString();
var ArrayExt = exports.ArrayExt = {
// abbrev
// [1,2,3,4,5].at(-1) => 5
at: function(a, i) {
if (i >= 0) return a[i];
return a[a.length + i];
}
// TODO make this work for non-array objects
, compact: function(a) {
var b = []
, i = a.length
;
while (i--) {
if (a[i] !== null && a[i] !== undefined) b[i] = a[i];
}
return b;
}
, first: function(a) { return a[0]; }
// Based on underscore.js's flatten
, flatten: function(a) {
return a.reduce(function(initial, elem) {
if (elem && elem.flatten) initial = initial.concat(elem.flatten());
else initial.push(elem);
return initial;
});
}
, grep: function(a, regex) {
return a.filter(function(v) { return regex.match(v); });
}
, last: function(a) { return a[a.length-1]; }
, max: function(a) {
return a.reduce(function(max, v) { return v > max ? v : max });
}
, min: function(a) {
return a.reduce(function(min, v) { return v < min ? v : min });
}
// pack
// partition
, pluck: function(a, /* key paths, ... */) {
var args = [].slice.call(arguments, 1);
args.unshift(a);
return pluck.apply(null, args);
}
, sortBy: function(arr, keyPath) {
return arr.slice().sort(function(a, b) {
var propA = drillInto(a)
, propB = drillInto(b);
if (propA < propB) return -1
if (propA > propB) return 1
return 0
});
}
, toString: function(a) {
return '[' + ArrayToString.call(a) + ']';
}
, unique: function(a) {
var b = []
, i = 0
, n = a.length
;
for (; i < n; ++i) {
if (b.indexOf(a[i]) === -1) b.push(a[i]);
}
return b;
}
};
// pluck
function getProp(thing, key) {
if (thing === null || thing === undefined) return thing
var prop = thing[key]
return typeof prop === 'function' ? prop.call(thing) : prop
}
function drillInto(thing, keyPath) {
return keyPath.split('.').reduce(function(memo, key) {
return getProp(memo, key)
}, thing)
}
function mapInto(thing /* , key paths, ... */) {
var keyPaths = [].slice.call(arguments, 1)
return keyPaths.map(function(keyPath) {
return drillInto(thing, keyPath)
})
}
function pluck(things /* , key paths, ... */) {
var keyPaths = [].slice.call(arguments, 1)
return things.map(function(thing) {
var results = mapInto.apply(null, [thing].concat(keyPaths))
if (results.length > 1) return results
return results[0]
})
}