| | |
| 1 | 1 | (function () { |
| 2 | 1 | "use strict"; |
| 3 | | |
| 4 | | /** |
| 5 | | * TODO |
| 6 | | * - some mozilla functions use .call but thisp could be "undefined" so -> can be replaced by direct call ?! |
| 7 | | * |
| 8 | | */ |
| 9 | | |
| 10 | 1 | var slice = Array.prototype.slice, |
| 11 | | hasOwnProperty = Object.hasOwnProperty, |
| 12 | | __clone, |
| 13 | | __rfilter; |
| 14 | | |
| 15 | | /** |
| 16 | | * Create an array given any type of argument |
| 17 | | * |
| 18 | | * @param {Mixed} item |
| 19 | | * @returns {Array} |
| 20 | | */ |
| 21 | 1 | module.exports.ize = function (item) { |
| 22 | 6 | if (item === null || item === undefined) { |
| 23 | 0 | return []; |
| 24 | | } |
| 25 | | |
| 26 | 6 | if (item instanceof Array) { |
| 27 | 0 | return item; |
| 28 | | } |
| 29 | | |
| 30 | 6 | if (hasOwnProperty.call(item, "callee")) { |
| 31 | 1 | return slice.call(item); |
| 32 | | } |
| 33 | | |
| 34 | | // TODO deal with Iterable objects like Collections! |
| 35 | | |
| 36 | 5 | return [ item ]; |
| 37 | | }; |
| 38 | | |
| 39 | 1 | module.exports.from = Array.ize; |
| 40 | | |
| 41 | | /** |
| 42 | | * Append any given number of arrays into a new one |
| 43 | | * @todo support any type of arguments |
| 44 | | * |
| 45 | | * @returns Array |
| 46 | | */ |
| 47 | 1 | module.exports.add = function () { |
| 48 | 2 | var i, |
| 49 | | j, |
| 50 | | ret = [], |
| 51 | | ar; |
| 52 | | |
| 53 | 2 | for (i = 0; i < arguments.length; ++i) { |
| 54 | 5 | ar = arguments[i]; |
| 55 | 5 | for (j = 0; j < ar.length; ++j) { |
| 56 | 15 | ret.push(ar[j]); |
| 57 | | } |
| 58 | | } |
| 59 | | |
| 60 | 2 | return ret; |
| 61 | | }; |
| 62 | | /** |
| 63 | | * Clone (could be recursive) a dense array |
| 64 | | * Note: only loop arrays not objects |
| 65 | | * |
| 66 | | * @param Array ar |
| 67 | | * @param Boolean deep |
| 68 | | * @returns Array |
| 69 | | */ |
| 70 | 1 | module.exports.clone = __clone = function (ar, deep) { |
| 71 | 4 | var i = ar.length, |
| 72 | | clone = new Array(i); |
| 73 | 4 | while (i--) { |
| 74 | 12 | if (deep && ar[i] instanceof Array) { |
| 75 | 0 | clone[i] = __clone(ar[i], true); |
| 76 | | } else { |
| 77 | 12 | clone[i] = ar[i]; |
| 78 | | } |
| 79 | | } |
| 80 | 4 | return clone; |
| 81 | | }; |
| 82 | | /** |
| 83 | | * Add an element at the specified index |
| 84 | | * |
| 85 | | * @param {Array} ar |
| 86 | | * @param {Mixed} o The object to add |
| 87 | | * @param {int} index The index position the element has to be inserted |
| 88 | | * @return {Boolean} true if o is successfully inserted |
| 89 | | */ |
| 90 | 1 | module.exports.insertAt = function (ar, o, index) { |
| 91 | 5 | if (index > -1 && index <= ar.length) { |
| 92 | 3 | ar.splice(index, 0, o); |
| 93 | 3 | return true; |
| 94 | | } |
| 95 | 2 | return false; |
| 96 | | }; |
| 97 | | /** |
| 98 | | * Get a random value, the array must be dense |
| 99 | | * |
| 100 | | * @param {Array} arr |
| 101 | | * @returns {Mixed} |
| 102 | | */ |
| 103 | 1 | module.exports.random = function (arr) { |
| 104 | 6 | var l = Math.floor(Math.random() * arr.length); |
| 105 | 6 | return arr[l]; |
| 106 | | }; |
| 107 | | /** |
| 108 | | * Create a new array removing duplicated values |
| 109 | | * |
| 110 | | * @param {Array} arr |
| 111 | | * @returns {Array} |
| 112 | | */ |
| 113 | 1 | module.exports.unique = function (arr) { |
| 114 | 1 | var ret = [], |
| 115 | | i; |
| 116 | | |
| 117 | 1 | for (i = 0; i < arr.length; ++i) { |
| 118 | 18 | if (ret.indexOf(arr[i]) === -1) { |
| 119 | 10 | ret.push(arr[i]); |
| 120 | | } |
| 121 | | } |
| 122 | | |
| 123 | 1 | return ret; |
| 124 | | }; |
| 125 | | |
| 126 | | /** |
| 127 | | * sort an array (must be dense) |
| 128 | | * |
| 129 | | * @param {Array} arr |
| 130 | | * @returns {Array} |
| 131 | | */ |
| 132 | 1 | module.exports.sortObject = function (arr, key) { |
| 133 | 2 | arr.sort(function (a, b) { |
| 134 | 12 | if ("string" === (typeof a[key])) { |
| 135 | 6 | return a.value.toLowerCase().localeCompare(b.value.toLowerCase()); |
| 136 | | } |
| 137 | 6 | return a[key] - b[key]; |
| 138 | | }); |
| 139 | | |
| 140 | 2 | return arr; |
| 141 | | }; |
| 142 | | /** |
| 143 | | * This function shuffles (randomizes the order of the elements in) an array. |
| 144 | | * credits - http://stackoverflow.com/questions/2450954/how-to-randomize-a-javascript-array |
| 145 | | * @note Given array is modified! |
| 146 | | * @param {Array} arr |
| 147 | | * @returns {Array} |
| 148 | | */ |
| 149 | 1 | module.exports.shuffle = function (arr) { |
| 150 | 1 | var currentIndex = arr.length, |
| 151 | | temporaryValue, |
| 152 | | randomIndex; |
| 153 | | |
| 154 | | // While there remain elements to shuffle.. |
| 155 | 1 | while (0 !== currentIndex) { |
| 156 | | |
| 157 | | // Pick a remaining element.. |
| 158 | 3 | randomIndex = Math.floor(Math.random() * currentIndex); |
| 159 | 3 | currentIndex -= 1; |
| 160 | | |
| 161 | | // And swap it with the current element. |
| 162 | 3 | temporaryValue = arr[currentIndex]; |
| 163 | 3 | arr[currentIndex] = arr[randomIndex]; |
| 164 | 3 | arr[randomIndex] = temporaryValue; |
| 165 | | } |
| 166 | | |
| 167 | 1 | return arr; |
| 168 | | }; |
| 169 | | |
| 170 | | /** |
| 171 | | * Iterates over each value in the array passing them to the callback function. |
| 172 | | * Returns an array with all the callback results |
| 173 | | * @param {Array} arr |
| 174 | | * @param {Function} fun |
| 175 | | * @returns {Array} |
| 176 | | */ |
| 177 | 1 | module.exports.rfilter = __rfilter = function (arr, fun /*, thisp */) { |
| 178 | 3 | if (arr === null) { |
| 179 | 0 | throw new TypeError(); |
| 180 | | } |
| 181 | | |
| 182 | 3 | var t = Object(arr), |
| 183 | | len = t.length >>> 0, |
| 184 | | res, |
| 185 | | thisp, |
| 186 | | i, |
| 187 | | val, |
| 188 | | r; |
| 189 | | |
| 190 | 3 | if ("function" !== typeof fun) { |
| 191 | 0 | throw new TypeError(); |
| 192 | | } |
| 193 | | |
| 194 | 3 | res = []; |
| 195 | 3 | thisp = arguments[1]; |
| 196 | 3 | for (i = 0; i < len; i++) { |
| 197 | 12 | if (i in t) { |
| 198 | 12 | val = t[i]; // in case fun mutates this |
| 199 | 12 | r = fun.call(thisp, val, i, t); |
| 200 | 12 | if (r !== undefined) { |
| 201 | 5 | res.push(r); |
| 202 | | } |
| 203 | | } |
| 204 | | } |
| 205 | | |
| 206 | 3 | return res; |
| 207 | | }; |
| 208 | | |
| 209 | 1 | module.exports.chunk = function (arr, size, preserve_keys) { |
| 210 | 2 | preserve_keys = preserve_keys || false; |
| 211 | | |
| 212 | 2 | var i = 0, |
| 213 | | j = 0, |
| 214 | | key, |
| 215 | | val, |
| 216 | | chunks = [[]]; |
| 217 | | |
| 218 | | //while( @list( $key, $value ) = @each( arr ) ) { |
| 219 | 2 | for (key = 0; key < arr.length; ++key) { |
| 220 | 10 | val = arr[key]; |
| 221 | | |
| 222 | | |
| 223 | 10 | if (chunks[i].length < size) { |
| 224 | 5 | if (preserve_keys) { |
| 225 | 2 | chunks[i][key] = val; |
| 226 | 2 | j++; |
| 227 | | } else { |
| 228 | 3 | chunks[i].push(val); |
| 229 | | } |
| 230 | | } else { |
| 231 | 5 | i++; |
| 232 | 5 | chunks.push([]); |
| 233 | | |
| 234 | 5 | if (preserve_keys) { |
| 235 | 3 | chunks[i][key] = val; |
| 236 | 3 | j++; |
| 237 | | } else { |
| 238 | 2 | j = 0; |
| 239 | 2 | chunks[i][j] = val; |
| 240 | | } |
| 241 | | } |
| 242 | | } |
| 243 | | |
| 244 | 2 | return chunks; |
| 245 | | }; |
| 246 | | /** |
| 247 | | * returns the values from a single column of the array-of-objects/arrays, identified by the column_key. |
| 248 | | * Optionally, you may provide an index_key to index the values in the returned array by the values from the index_key column in the input array. |
| 249 | | */ |
| 250 | 1 | module.exports.column = function (arr, field) { |
| 251 | 0 | return Array.rfilter(arr, function (x) { return x ? x[field] : undefined; }); |
| 252 | | }; |
| 253 | | /** |
| 254 | | * Append any number of arrays into the first one |
| 255 | | * |
| 256 | | * @param {Array} dst |
| 257 | | * @returns {Array} |
| 258 | | */ |
| 259 | 1 | module.exports.combine = function (dst) { |
| 260 | 2 | var i, |
| 261 | | j, |
| 262 | | ar; |
| 263 | | |
| 264 | 2 | for (j = 1; j < arguments.length; ++j) { |
| 265 | 3 | ar = arguments[j]; |
| 266 | | |
| 267 | 3 | for (i = 0; i < ar.length; ++i) { |
| 268 | 7 | dst.push(ar[i]); |
| 269 | | } |
| 270 | | } |
| 271 | | }; |
| 272 | | /** |
| 273 | | * Counts all the values of an array |
| 274 | | */ |
| 275 | 1 | module.exports.countValues = function (arr, ci) { |
| 276 | 2 | ci = ci || false; |
| 277 | 2 | var i, |
| 278 | | counter = {}, |
| 279 | | val; |
| 280 | | |
| 281 | 2 | for (i = 0; i < arr.length; ++i) { |
| 282 | 22 | val = arr[i]; |
| 283 | 22 | if (ci && "string" === typeof val) { |
| 284 | 10 | val = val.toLowerCase(); |
| 285 | | } |
| 286 | | |
| 287 | 22 | if (counter[val]) { |
| 288 | 11 | ++counter[val]; |
| 289 | | } else { |
| 290 | 11 | counter[val] = 1; |
| 291 | | } |
| 292 | | } |
| 293 | | |
| 294 | 2 | return counter; |
| 295 | | }; |
| 296 | | /** |
| 297 | | * Returns a copy of the array padded to size specified by size with value value. If size is positive then the array is padded on the right, if it"s negative then on the left. If the absolute value of size is less than or equal to the length of the array then no padding takes place |
| 298 | | */ |
| 299 | 1 | module.exports.pad = function (arr, size, value) { |
| 300 | 3 | if (Math.abs(size) <= arr.length) { |
| 301 | 1 | return arr; |
| 302 | | } |
| 303 | 2 | var out = [], |
| 304 | | i, |
| 305 | | len; |
| 306 | | |
| 307 | 2 | if (size > 0) { |
| 308 | 1 | for (i = 0; i < size; ++i) { |
| 309 | 5 | out[i] = i < arr.length ? arr[i] : value; |
| 310 | | } |
| 311 | | } else { |
| 312 | 1 | size = Math.abs(size); |
| 313 | 1 | len = size - arr.length; |
| 314 | 1 | for (i = 0; i < size; ++i) { |
| 315 | 7 | out[i] = i < len ? value : arr[i - len]; |
| 316 | | } |
| 317 | | } |
| 318 | | |
| 319 | 2 | return out; |
| 320 | | }; |
| 321 | | /** |
| 322 | | * Calculate the product of values in an array |
| 323 | | */ |
| 324 | 1 | module.exports.product = function (arr) { |
| 325 | 1 | var sum = 1, |
| 326 | | len = arr.length, |
| 327 | | i; |
| 328 | | |
| 329 | 1 | for (i = 0; i < len; i++) { |
| 330 | 4 | sum *= parseFloat(arr[i]); // be sure it"s a number.. |
| 331 | | } |
| 332 | | |
| 333 | 1 | return sum; |
| 334 | | }; |
| 335 | | /** |
| 336 | | * Picks one or more random entries out of an array, and returns the key (or keys) of the random entries. |
| 337 | | */ |
| 338 | 1 | module.exports.rand = function (arr, len) { |
| 339 | 0 | var out = [], |
| 340 | | i; |
| 341 | 0 | len = len || 1; |
| 342 | | |
| 343 | 0 | for (i = 0; i < len; ++i) { |
| 344 | 0 | out.push(Math.floor(Math.random() * arr.length)); |
| 345 | | } |
| 346 | | |
| 347 | 0 | return out; |
| 348 | | }; |
| 349 | | |
| 350 | 1 | module.exports.dense = function (arr) { |
| 351 | 1 | var out = []; |
| 352 | | |
| 353 | 1 | arr.forEach(function (val) { |
| 354 | 2 | out.push(val); |
| 355 | | }); |
| 356 | | |
| 357 | 1 | return out; |
| 358 | | }; |
| 359 | | |
| 360 | 1 | module.exports.sum = function (arr) { |
| 361 | 3 | var sum = 0, |
| 362 | | len = arr.length, |
| 363 | | i; |
| 364 | | |
| 365 | 3 | for (i = 0; i < len; i++) { |
| 366 | 12 | sum += parseFloat(arr[i]); // be sure it"s a number.. |
| 367 | | } |
| 368 | | |
| 369 | 3 | return sum; |
| 370 | | }; |
| 371 | | |
| 372 | | /** |
| 373 | | * Fill an array with values |
| 374 | | */ |
| 375 | 1 | module.exports.fill = function (start, count, value) { |
| 376 | 2 | var arr = [], |
| 377 | | len = start + count, |
| 378 | | i; |
| 379 | | |
| 380 | 2 | for (i = start; i < len; ++i) { |
| 381 | 10 | arr[i] = value; |
| 382 | | } |
| 383 | | |
| 384 | 2 | return arr; |
| 385 | | }; |
| 386 | | /** |
| 387 | | * Return the values from a single column in the input array |
| 388 | | */ |
| 389 | 1 | module.exports.column = function (arr, field) { |
| 390 | 15 | return __rfilter(arr, function (x) { return x[field]; }); |
| 391 | | }; |
| 392 | | |
| 393 | | /** |
| 394 | | * returns an object with the same values keys given a property of the object |
| 395 | | * @throws if the field is undefined! |
| 396 | | */ |
| 397 | 1 | module.exports.kmap = function (arr, field) { |
| 398 | 1 | var ret = {}; |
| 399 | | |
| 400 | 1 | arr.forEach(function (v) { |
| 401 | 3 | if (!v[field]) { |
| 402 | 0 | console.log(v); |
| 403 | 0 | throw new Error("field not found in v"); |
| 404 | | } |
| 405 | | |
| 406 | 3 | ret[v[field]] = v; |
| 407 | | }); |
| 408 | | |
| 409 | 1 | return ret; |
| 410 | | }; |
| 411 | | |
| 412 | | }()); |