UNPKG

arr

Version:

JavaScript utilities for arrays.

722 lines (642 loc) 14.5 kB
/*! * arr <https://github.com/jonschlinkert/arr> * * Copyright (c) 2014 Jon Schlinkert, contributors. * Licensed under the MIT License */ 'use strict'; /** * Module dependencies */ var assert = require('assert'); var makeIterator = require('make-iterator'); var typeOf = require('kind-of'); /** * Custom `indexOf` implementation that works with sparse arrays * to provide consisten results in any environment or browser. * * @param {Array} `arr` * @param {*} `value` * @param {Array} `start` Optionally define a starting index. * @return {Array} */ function indexOf(arr, value, start) { start = start || 0; if (arr == null) { return -1; } var len = arr.length; var i = start < 0 ? len + start : start; while (i < len) { if (arr[i] === value) { return i; } i++; } return -1; } /** * Return `true` if the given `array` contains `value`. * Alias for `[indexOf]`. * * @param {Array} `array` The array to check. * @param {*} `value` * @return {Boolean} */ function contains(arr, val) { return indexOf(arr, value); } /** * Return `true` if the callback returns `true` * for every element in the `array`. * * @param {Array} `array` The array to check. * @param {*} `value` * @return {Boolean} */ function every(arr, cb, thisArg) { cb = makeIterator(cb, thisArg); var result = true; if (arr == null) { return result; } var len = arr.length; var i = -1; while (++i < len) { if (!cb(arr[i], i, arr)) { result = false; break; } } return result; } /** * Like JavaScript's native filter method, but faster. * * @param {Array} `arr` The array to filter * @param {Function} `cb` Callback function. * @param {Array} `thisArg` * @return {Array} */ function filter(arr, cb, thisArg) { cb = makeIterator(cb, thisArg); if (arr == null) { return []; } var len = arr.length; var res = []; for (var i = 0; i < len; i++) { var ele = arr[i]; if (cb(ele, i, arr)) { res.push(ele); } } return res; } /** * Filter `array`, returning only the values of the given `type`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * * utils.filterType(arr, 'object'); * //=> [{a: 'b'}, {c: 'd'}] * ``` * * @param {Array} `array` * @param {String} `type` Native type, e.g. `string`, `object` * @return {Boolean} * @api public */ function filterType(arr, type) { var len = arr.length; var res = []; for (var i = 0; i < len; i++) { var ele = arr[i]; if (typeOf(ele) === type) { res.push(ele); } } return res; } /** * Return the first index of the given `type`, or `-1` if not found. * * ```js * utils.firstIndex(['a', 1, 'b', 2, {c: 'd'}, 'c'], 'object'); * //=> 4 * ``` * * @param {Array} `array` * @param {String} `type` Native type, e.g. `string`, `object` * @return {Boolean} * @api public */ function firstIndex(arr, cb, thisArg) { cb = makeIterator(cb, thisArg); if (arr == null) { return -1; } var len = arr.length; for (var i = 0; i < len; i++) { if (cb(arr[i], i, arr)) { return i; } } return -1; } /** * Return the first index of the given `type`, or `-1` if not found. * * ```js * utils.firstIndex(['a', 1, 'b', 2, {c: 'd'}, 'c'], 'object'); * //=> 4 * ``` * * @param {Array} `array` * @param {String} `type` Native type, e.g. `string`, `object` * @return {Boolean} * @api public */ function findFirst(arr, cb, thisArg) { var i = firstIndex(arr, cb, thisArg); return i >= 0 ? arr[i] : void(42); } /** * Return the first index of the given `type`, or `-1` if not found. * * ```js * utils.firstIndex(['a', 1, 'b', 2, {c: 'd'}, 'c'], 'object'); * //=> 4 * ``` * * @param {Array} `array` * @param {String} `type` Native type, e.g. `string`, `object` * @return {Boolean} * @api public */ function lastIndex(arr, cb, thisArg) { cb = makeIterator(cb, thisArg); if (arr == null) { return -1; } var len = arr.length - 1; for (var i = len; i >= 0; i--) { var key = arr[i]; if (cb(key, i, arr)) { return i; } } return -1; } /** * Return the first index of the given `type`, or `-1` if not found. * * ```js * utils.firstIndex(['a', 1, 'b', 2, {c: 'd'}, 'c'], 'object'); * //=> 4 * ``` * * @param {Array} `array` * @param {String} `type` Native type, e.g. `string`, `object` * @return {Boolean} * @api public */ function findLast(arr, cb, thisArg) { var i = lastIndex(arr, cb, thisArg); return i >= 0 ? arr[i] : void(42); } /** * Filter `array`, returning only the numbers. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * * utils.numbers(arr); * //=> [1, 2] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the number to return, otherwise all numbers are returned. * @return {Array} Array of numbers or empty array. * @api public */ function hasType(arr, type) { var i = firstIndex(arr, isType(type)); return i === -1 ? false : true; } /** * Filter `array`, returning only the numbers. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * * utils.numbers(arr); * //=> [1, 2] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the number to return, otherwise all numbers are returned. * @return {Array} Array of numbers or empty array. * @api public */ function numbers(arr, i) { var values = filterType(arr, 'number'); return i ? values[i] : values; } /** * Filter `array`, returning only the strings. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * * utils.strings(arr); * //=> ['a', 'b', 'c'] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the string to return, otherwise all strings are returned. * @return {Array} Array of strings or empty array. * @api public */ function strings(arr, i) { var values = filterType(arr, 'string'); return i ? values[i] : values; } /** * Filter `array`, returning only the objects. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * * utils.objects(arr); * //=> [{a: 'b'}, {c: 'd'}] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the object to return, otherwise all objects are returned. * @return {Array} Array of objects or empty array. * @api public */ function objects(arr, i) { var values = filterType(arr, 'object'); return i ? values[i] : values; } /** * Filter `array`, returning only the functions. * * ```js * var one = function() {}; * var two = function() {}; * var arr = ['a', {a: 'b'}, 1, one, 'b', 2, {c: 'd'}, two, 'c']; * * utils.functions(arr); * //=> [one, two] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the function to return, otherwise all functions are returned. * @return {Array} Array of functions or empty array. * @api public */ function functions(arr, i) { var values = filterType(arr, 'function'); return i ? values[i] : values; } /** * Filter `array`, returning only the arrays. * * ```js * var arr = ['a', ['aaa'], 1, 'b', ['bbb'], 2, {c: 'd'}, 'c']; * * utils.objects(arr); * //=> [['aaa'], ['bbb']] * ``` * * @param {Array} `array` * @param {Array} `index` Optionally specify the index of the array to return, otherwise all arrays are returned. * @return {Array} Array of arrays or empty array. * @api public */ function arrays(arr, i) { var values = filterType(arr, 'array'); return i ? values[i] : values; } /** * Return the first element in `array`, or, if a callback is passed, * return the first value for which the returns true. * * ```js * var arr = ['a', {a: 'b'}, 1, one, 'b', 2, {c: 'd'}, two, 'c']; * * utils.first(arr); * //=> 'a' * * utils.first(arr, isType('object')); * //=> {a: 'b'} * * utils.first(arr, 'object'); * //=> {a: 'b'} * ``` * * @param {Array} `array` * @return {*} * @api public */ function first(arr, cb, thisArg) { if (arguments.length === 1) { return arr[0]; } if (typeOf(cb) === 'string') { return findFirst(arr, isType(cb)); } return findFirst(arr, cb, thisArg); } /** * Return the last element in `array`, or, if a callback is passed, * return the last value for which the returns true. * * ```js * // `one` and `two` are functions * var arr = ['a', {a: 'b'}, 1, one, 'b', 2, {c: 'd'}, two, 'c']; * * utils.last(arr); * //=> 'c' * * utils.last(arr, isType('function')); * //=> two * * utils.last(arr, 'object'); * //=> {c: 'd'} * ``` * @param {Array} `array` * @return {*} * @api public */ function last(arr, cb, thisArg) { if (arguments.length === 1) { return arr[arr.length - 1]; } if (typeOf(cb) === 'string') { return findLast(arr, isType(cb)); } return findLast(arr, cb, thisArg); } /** * Get the last element in `array` of the given `type`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastOfType(arr, 'number'); * //=> 2 * ``` * @param {Array} `array` * @param {String} `type` The native type to get. * @return {*} * @api public */ function lastOfType(arr, type) { return last(filterType(arr, type)); } /** * Get the first element in `array` of the given `type`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstOfType(arr, 'number'); * //=> 1 * ``` * @param {Array} `array` * @param {String} `type` The native type to get. * @return {*} * @api public */ function firstOfType(arr, type) { return filterType(arr, type)[0]; } /** * Returns `true` if the last element in `array` is the given `type`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastIsType(arr, 'number'); * //=> false * ``` * @param {Array} `array` * @param {String} `type` The native type to check. * @return {Boolean} * @api public */ function lastIsType(arr, type) { return typeOf(last(arr)) === type; } /** * Returns `true` if the first element in `array` is the given `type`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstIsType(arr, 'string'); * //=> true * ``` * @param {Array} `array` * @param {String} `type` The native type to check. * @return {Boolean} * @api public */ function firstIsType(arr, type) { return typeOf(arr[0]) === type; } /** * Get the first string in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstString(arr, 'string'); * //=> 'a' * ``` * @param {Array} `array` * @return {String} * @api public */ function firstString(arr) { return firstOfType(arr, 'string'); } /** * Get the last string in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastString(arr, 'string'); * //=> 'c' * ``` * @param {Array} `array` * @return {String} * @api public */ function lastString(arr) { return lastOfType(arr, 'string'); } /** * Get the first function in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstFunction(arr, 'function'); * //=> 'a' * ``` * @param {Array} `array` * @return {Function} * @api public */ function firstFunction(arr) { return firstOfType(arr, 'function'); } /** * Get the last function in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastFunction(arr, 'function'); * //=> 'a' * ``` * @param {Array} `array` * @return {Function} * @api public */ function lastFunction(arr) { return lastOfType(arr, 'function'); } /** * Get the first number in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstNumber(arr, 'number'); * //=> '1' * ``` * @param {Array} `array` * @return {Function} * @api public */ function firstNumber(arr) { return firstOfType(arr, 'number'); } /** * Get the last number in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastNumber(arr, 'number'); * //=> '2' * ``` * @param {Array} `array` * @return {Function} * @api public */ function lastNumber(arr) { return lastOfType(arr, 'number'); } /** * Get the first object in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * firstObject(arr); * //=> {a: 'b'} * ``` * @param {Array} `array` * @return {Object} * @api public */ function firstObject(arr) { return firstOfType(arr, 'object'); } /** * Get the last object in `array`. * * ```js * var arr = ['a', {a: 'b'}, 1, 'b', 2, {c: 'd'}, 'c']; * lastObject(arr); * //=> {c: 'd'} * ``` * @param {Array} `array` * @return {Object} * @api public */ function lastObject(arr) { return lastOfType(arr, 'object'); } /** * Returns a function that returns `true` if a * value is the given type. * * @param {String} type * @return {Boolean} * @api private */ function isType(type) { return function (val) { return typeOf(val) === type; }; } /** * Utils for getting the `typeof` a value. * * @param {*} `val` * @return {*} * @api private */ function isString(val) { return typeOf(val) === 'string'; } function typeOf(val) { return typeOf(val); } function isFunction(val) { return typeOf(val) === 'function'; } function isArray(val) { return typeOf(val) === 'array'; } function isObject(val) { return typeOf(val) === 'object'; } /** * Export methods * * @type {Object} */ exports.arrays = arrays; exports.contains = contains; exports.every = every; exports.filter = filter; exports.filterType = filterType; exports.findFirst = findFirst; exports.findLast = findLast; exports.first = first; exports.firstFunction = firstFunction; exports.firstIndex = firstIndex; exports.firstIsType = firstIsType; exports.firstNumber = firstNumber; exports.firstObject = firstObject; exports.firstOfType = firstOfType; exports.firstString = firstString; exports.functions = functions; exports.hasType = hasType; exports.indexOf = indexOf; exports.isArray = isArray; exports.isFunction = isFunction; exports.isObject = isObject; exports.isString = isString; exports.isType = isType; exports.last = last; exports.lastFunction = lastFunction; exports.lastIndex = lastIndex; exports.lastIsType = lastIsType; exports.lastNumber = lastNumber; exports.lastObject = lastObject; exports.lastOfType = lastOfType; exports.lastString = lastString; exports.numbers = numbers; exports.objects = objects; exports.strings = strings;