'use strict'; /*@ Ox.compact Returns an array w/o undefined values > Ox.compact([null,,1,,2,,3]) [1, 2, 3] @*/ Ox.compact = function(arr) { return arr.filter(function(val) { return !Ox.isNull(val) && !Ox.isUndefined(val); }); }; /*@ Ox.flatten Flattens an array > Ox.flatten([1, [2, [3], 2], 1]) [1, 2, 3, 2, 1] @*/ Ox.flatten = function(arr) { // fixme: can this work for objects too? var ret = []; arr.forEach(function(val) { if (Ox.isArray(val)) { Ox.flatten(val).forEach(function(val) { ret.push(val); }); } else { ret.push(val); } }); return ret; }; /*@ Ox.merge Merges an array with one or more other arrays > Ox.merge([1], [2, 3, 2], [1]) [1, 2, 3, 2, 1] > Ox.merge(1, [2, 3, 2], 1) [1, 2, 3, 2, 1] @*/ Ox.merge = function(arr) { arr = Ox.toArray(arr); Ox.forEach(Array.prototype.slice.call(arguments, 1), function(arg) { Ox.forEach(Ox.toArray(arg), function(val) { arr.push(val); }); }); return arr; }; /*@ Ox.range Python-style range (stop) -> <[n]> range Returns an array of integers from 0 (inclusive) to stop (exclusive). (start, stop) -> <[n]> range Returns an array of integers from start (inclusive) to stop (exclusive). (start, stop, step) -> <[n]> range Returns an array of numbers from start (inclusive) to stop (exclusive), incrementing by step. start Start value stop Stop value step Step value > Ox.range(3) [0, 1, 2] > Ox.range(1, 4) [1, 2, 3] > Ox.range(3, 0) [3, 2, 1] > Ox.range(1, 2, 0.5) [1, 1.5] > Ox.range(-1, -2, -0.5) [-1, -1.5] @*/ Ox.range = function() { var args = Ox.makeArray(arguments), arr = []; args.push(function(i) { arr.push(i); }); Ox.loop.apply(null, args); return arr; }; (function() { function getSortValues(arr, fn) { var arr_ = fn ? arr.map(fn) : arr, len, matches = {}, sort = {}; // find leading numbers arr.forEach(function(val, i) { var match = /^\d+/.exec(arr_[i]); matches[val] = match ? match[0] : ''; }); // get length of longest leading number len = Ox.max(Ox.map(matches, function(val) { return val.length; })); // pad leading numbers, make lowercase, // and remove leading non-word characters arr.forEach(function(val, i) { sort[val] = ( matches[val] ? arr_[i].toString().replace( matches[val], Ox.pad(matches[val], len) ) : arr_[i] ).toLowerCase().replace(/^\W+/, ''); }); return sort; } /*@ Ox.sort Sorts an array, handling leading digits and ignoring capitalization (arr) -> Sorted array (arr, fn) -> Sorted array arr Array fn Optional map function that returns the value for the array element > Ox.sort(['"z"', '10', '9', 'B', 'a']) ['9', '10', 'a', 'B', '"z"'] > Ox.sort([{id: 0, name: '80 Days'}, {id: 1, name: '8 Women'}], function(v) {return v.name}) [{id: 1, name: '8 Women'}, {id: 0, name: '80 Days'}] @*/ Ox.sort = function(arr, fn) { var sort = getSortValues(fn ? arr.map(fn) : arr); return arr.sort(function(a, b) { a = fn ? fn(a) : a; b = fn ? fn(b) : b; var ret = 0; if (sort[a] < sort[b]) { ret = -1; } else if (sort[a] > sort[b]) { ret = 1; } return ret; }); }; /*@ Ox.sortBy Sorts an array of objects by given properties (arr, by) -> Sorted array arr <[o]> Array of objects by <[s]> Array of object keys (asc: 'foo' or '+foo', desc: '-foo') fn Optional functions, per key, that return the sort value > Ox.sortBy([{x: 1, y: 1}, {x: 1, y: 2}, {x: 2, y: 2}], ['+x', '-y']) [{x: 1, y: 2}, {x: 1, y: 1}, {x: 2, y: 2}] > Ox.sortBy([{id: 0, name: '80 Days'}, {id: 1, name: '8 Women'}], ['name']) [{id: 1, name: '8 Women'}, {id: 0, name: '80 Days'}] @*/ Ox.sortBy = function(arr, by, fn) { var length = by.length, values = {}; by = by.map(function(v) { return { key: v.replace(/^[\+\-]/g, ''), operator: v[0] == '-' ? '-' : '+' }; }); fn = fn || {}; by.map(function(v) { return v.key; }).forEach(function(key) { values[key] = getSortValues(arr.map(function(v) { return v[key]; }), fn[key]); }); return arr.sort(function(a, b) { var aValue, bValue, index = 0, key, ret = 0; while (ret == 0 && index < length) { key = by[index].key; aValue = values[key][a[key]]; bValue = values[key][b[key]]; if (aValue < bValue) { ret = by[index].operator == '+' ? -1 : 1; } else if (aValue > bValue) { ret = by[index].operator == '+' ? 1 : -1; } else { index++; } } return ret; }); }; }()); /*@ Ox.unique Returns an array without duplicate values > Ox.unique([1, 2, 3, 2, 1]) [1, 2, 3] > Ox.unique([NaN, NaN]) [] @*/ Ox.unique = function(arr) { return Ox.filter(arr, function(val, i) { return arr.indexOf(val) == i; }); }; /*@ Ox.zip Zips an array of arrays > Ox.zip([[0, 1], [2, 3], [4, 5]]) [[0, 2, 4], [1, 3, 5]] > Ox.zip([0, 1, 2], [3, 4, 5]) [[0, 3], [1, 4], [2, 5]] @*/ Ox.zip = function() { var args = arguments.length == 1 ? arguments[0] : Ox.makeArray(arguments), arr = []; args[0].forEach(function(v, i) { arr[i] = []; args.forEach(function(v) { arr[i].push(v[i]); }); }); return arr; };