We use cookies to make our website more effective. By using our website you agree to our privacy policy.

Source: arrays.js

/**
 * arrays.js is part of Aloha Editor project http://www.alohaeditor.org
 *
 * Aloha Editor ● JavaScript Content Editing Library
 * Copyright (c) 2010-2015 Gentics Software GmbH, Vienna, Austria.
 * Contributors http://www.alohaeditor.org/docs/contributing.html
 * @namespace arrays
 */
define(['functions'], function (Fn) {
	'use strict';

	/**
	 * Does a shallow compare of two arrays.
	 *
	 * @param {Array} a
	 *        An array to compare.
	 * @param {Array} b
	 *        A second array to compare with `a`.
	 * @param {function(*, *):number} equalFn
	 *        A custom comparison function that accepts two values a and b from
	 *        the given arrays and returns true or false for equal and not equal
	 *        respectively.
	 *
	 *        If no equalFn is provided, the algorithm will use the strict
	 *        equals operator.
	 * @return {boolean}
	 *         True if all items in a and b are equal, false if not.
	 * @memberOf arrays
	 */
	function equal(a, b, equalFn) {
		var i,
			len = a.length;
		if (len !== b.length) {
			return false;
		}
		equalFn = equalFn || Fn.strictEquals;
		for (i = 0; i < len; i++) {
			if (!equalFn(a[i], b[i])) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Returns true if the given Array `xs` contains the value `x`.
	 *
	 * @param {Array} xs
	 * @param {*} x
	 *        A value to search for in the given array.
	 * @return {boolean}
	 *         True of argument `x` is an element of the set `xs`.
	 * @memberOf arrays
	 */
	function contains(xs, x) {
		return -1 !== xs.indexOf(x);
	}

	/**
	 * Returns all items in the array `xs` that are also contained in array
	 * `zs`.
	 *
	 * @param {Array} xs
	 * @param {Array} zs
	 * @return {Array}
	 *         The intersection of the sets `xs` and `zs`.
	 * @memberOf arrays
	 */
	function intersect(xs, zs) {
		return xs.filter(function (x) {
			return contains(zs, x);
		});
	}

	/**
	 * Returns the relative difference of array `zs` in `xs`:
	 * All items in the array `xs` that are not contained in array `zs`.
	 *
	 * @param {Array} xs
	 * @param {Array} zs
	 * @return {Array}
	 *         The difference of the sets `xs` and `zs`.
	 * @memberOf arrays
	 */
	function difference(xs, zs) {
		return xs.filter(function (x) {
			return !contains(zs, x);
		});
	}

	/**
	 * Returns the last item in the given Array.
	 *
	 * @param {Array} xs
	 * @return {*}
	 *         Last item in xs, or null if the given array is empty.
	 * @memberOf arrays
	 */
	function last(xs) {
		return xs.length ? xs[xs.length - 1] : null;
	}

	/**
	 * Coerces the given object (NodeList, arguments) to an array.
	 *
	 * This implementation works on modern browsers and IE >= 9. For IE
	 * < 9 a shim can be used, available here:
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
	 *
	 * @param arrayLikeObject {*}
	 * @return {Array.<*>}
	 * @memberOf arrays
	 */
	function coerce(arrayLikeObject) {
		return Array.prototype.slice.call(arrayLikeObject);
	}

	/**
	 * Like Array.prototype.map() except expects the given function to return
	 * arrays which will be concatenated together into the resulting array.
	 *
	 * Related to partition() in the sense that
	 * mapcat(partition(xs, n), identity) == xs.
	 *
	 * Don't use Array.prototype.concat.apply():
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
	 * "The consequences of applying a function with too many arguments
	 * (think more than tens of thousands of arguments) vary across
	 * engines (JavaScriptCore has hard-coded argument limit of 65536),
	 * because the limit (indeed even the nature of any
	 * excessively-large-stack behavior) is unspecified. "
	 *
	 * @param xs {Array.<*>}
	 * @param fn {function(*):Array.<*>}
	 * @return {Array.<*>}
	 * @memberOf arrays
	 */
	function mapcat(xs, fn) {
		return xs.reduce(function(result, x) {
			return result.concat(fn(x));
		}, []);
	}

	/**
	 * Partitions the given array xs into an array of arrays where each
	 * nested array is a subsequence of xs of length n.
	 *
	 * See mapcat().
	 *
	 * @param xs {Array.<*>}
	 * @param n {number}
	 * @return {Array.<Array.<*>>}
	 * @memberOf arrays
	 */
	function partition(xs, n) {
		return xs.reduce(function (result, x) {
			var l = last(result);
			if (l && l.length < n) {
				l.push(x);
			} else {
				result.push([x]);
			}
			return result;
		}, []);
	}

	/**
	 * Similar to some(), except that it returns an index into the given array
	 * for the first element for which `pred` returns true.
	 *
	 * If none return true, -1 is returned.
	 *
	 * @param {Array.<*>}           xs
	 * @param {function(*):boolean} pred
	 * @return {*}
	 * @memberOf arrays
	 */
	function someIndex(xs, pred) {
		var result = -1;
		xs.some(function (x, i) {
			if (pred(x)) {
				result = i;
				return true;
			}
		});
		return result;
	}

	/**
	 * Similar to 
	 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
	 * Except, instead of returning true, returns the first value in the array
	 * for which the `pred` returns true.
	 *
	 * @param  {Array.<*>}           xs
	 * @param  {function(*):boolean} pred
	 * @return {*} One of xs
	 * @memberOf arrays
	 */
	function some(xs, pred) {
		var index = someIndex(xs, pred);
		return -1 === index ? null : xs[index];
	}

	/**
	 * Splits the list into two parts using the given predicate.
	 *
	 * The first element will be the "prefix," containing all elements of `list` before
	 * the element that returns true for the predicate.
	 *
	 * The second element is equal to dropWhile(list).
	 *
	 * @param  {Array<*>}            list
	 * @param  {function(*):boolean} predicate
	 * @return {Array<Array<*>>}     The prefix and suffix of `list`
	 * @memberOf arrays
	 */
	function split(xs, predicate) {
		var end = someIndex(xs, predicate);
		end = -1 === end ? xs.length : end;
		return [xs.slice(0, end), xs.slice(end)];
	}

	/**
	 * Creates a new array that contains a unique list of entries
	 * created from the old array. Example:
	 * [1, 2, 2, 3, 2, 4] => [1, 2, 3, 4]
	 *
	 * @param  {Array.<*>} arr
	 * @return {Array.<*>}
	 * @memberOf arrays
	 */
	function unique(arr) {
		var set = [];
		arr.forEach(function (entry) {
			if (set.indexOf(entry) === -1) {
				set.push(entry);
			}
		});
		return set;
	}

	/**
	 * This function is missing documentation.
	 * @TODO Complete documentation.
	 * @memberOf arrays
	 */
	function refill(arrays) {
		var receivers = coerce(arguments).slice(1);
		for (var i = 0; i < arrays.length; i++) {
			if (!arrays[i] || !receivers[i]) {
				return;
			}
			receivers[i].length = 0;
			Array.prototype.splice.apply(receivers[i], [0, 0].concat(arrays[i]));
		}
	}

	/**
	 * Returns true if the given value is an array.
	 * @memberOf arrays
	 */
	function is(obj) {
		return (Object.prototype.toString.call(obj) === '[object Array]');
	}

	return {
		contains   : contains,
		difference : difference,
		equal      : equal,
		intersect  : intersect,
		is         : is,
		last       : last,
		coerce     : coerce,
		mapcat     : mapcat,
		partition  : partition,
		some       : some,
		someIndex  : someIndex,
		split      : split,
		unique     : unique,
		refill     : refill
	};
});
comments powered by Disqus