Source

array.js

//#region Array
/**
 * Counts the items in an array, returning a separate count for each object.
 * @returns {Object}
 * @memberOf array
 * @function
 * @example
 * _$.count(['a', 'b', 'c', 'd', 'e', 'f'])//{'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'f': 1}
 *
 * //But if you have multiple items:
 * _$.count(['a', 'a', b', 'b', 'c', 'd', 'e']);//{'a': 2, 'b': 2, 'c': 1, 'd': 1, 'e': 1}
 * @param {Array} arr The array to count items in.
 */
export let count = (arr = req("array", "array")) =>
	arr.reduce((counts, item) => {
		counts[item] = (counts[item] || 0) + 1;
		return counts;
	}, {});

/**
 * Returns the difference between two arrays or strings.
 * @memberOf array
 * @function
 * @returns {Array|String} The difference between two arrays or strings.
 * @example
 * console.log(_$.arrayDiff(['a', 'b'], ['a', 'b', 'c', 'd'])); // ["c", "d"]
 * @param {Array|String} a1 The first array or string
 * @param {Array|String} a2 The 2nd array or string.
 */
export let arrayDiff = (
	a1 = req("array", "array 1"),
	a2 = req("array", "array 2"),
) => {
	var a = [],
		diff = [];
	for (var i = 0; i < a1.length; i++) {
		a[a1[i]] = true;
	}
	for (var i = 0; i < a2.length; i++) {
		if (a[a2[i]]) {
			delete a[a2[i]];
		} else {
			a[a2[i]] = true;
		}
	}
	for (var k in a) {
		diff.push(k);
	}
	return diff;
};

/**
 * Gets the difference between two strings.
 * @memberOf array
 * @function
 * @param {String} text1 The 1st text to compare
 * @param {String} text2 The 2nd text to compare with the 1st one.
 * @example
 * console.log(_$.diff("hello earthlings", "hello world"); // [[6,8],[9,16]]
 * @returns {Array.<Array.<number>>} An array of arrays, each array in the main array contains 2 numbers, the start and then end of the difference.
 */
export let diff = function (
	text1 = req("string", "Text 1"),
	text2 = req("string", "Text 2"),
) {
	//Takes in two strings
	//Returns an array of the span of the differences
	//So if given:
	// text1: "that is number 124"
	// text2: "this is number 123"
	//It will return:
	// [[2,4],[17,18]]
	//If the strings are of different lengths, it will check up to the end of text1
	//If you want it to do case-insensitive difference, just convert the texts to lowercase before passing them in
	var diffRange = [];
	var currentRange = undefined;
	for (var i = 0; i < text1.length; i++) {
		if (text1[i] != text2[i]) {
			//Found a diff!
			if (currentRange == undefined) {
				//Start a new range
				currentRange = [i];
			}
		}
		if (currentRange != undefined && text1[i] == text2[i]) {
			//End of range!
			currentRange.push(i);
			diffRange.push(currentRange);
			currentRange = undefined;
		}
	}
	//Push any last range if there's still one at the end
	if (currentRange != undefined) {
		currentRange.push(i);
		diffRange.push(currentRange);
	}
	return diffRange;
};

/**
 * Removes an item from the array specified.
 * @memberOf array
 * @function
 * @param {Array} array The array to remove the item from.
 * @param {*} item The item to remove.
 * @example
 * console.log(_$.remove([5, 4, 3, 2, 1], 4)); // [5, 3, 2, 1]
 */
export let remove = (
	array = req("array", "array"),
	item = req(undefined, "item"),
) => {
	if (typeof array === "string") {
		return array.replace(item, "");
	}
	if (typeof array === "object") {
		array[`${item}`] = undefined;
		array = _$.clone(array, (itm) => itm !== undefined);
		return array;
	}
	if (array.indexOf(item) > -1) {
		array.splice(array.indexOf(item), 1);
	}
	return array;
};
/**
 * Splices an ArrayBuffer.
 * @function
 * @memberOf array
 * @param {ArrayBuffer|Buffer} arr The ArrayBuffer to splice.
 * @param {Number} start The start index.
 * @param {Number} end The end index.
 * @param {Boolean} [endian=false] Whether to use big endian or not.
 * @returns {Number} The hex representation of part of the ArrayBuffer.
 */
export let spliceArrayBuffer = (
	arr = req("ArrayBuffer"),
	start = req("number"),
	end = req("number"),
	endian = false,
) => {
	var direction = endian ? -1 : 1;
	if (endian) [start, end] = [end, start];
	start = Math.floor(start);
	end = Math.floor(end) + direction;
	for (var i = start, value = 0; i != end; i += direction)
		value = 256 * value + arr[i];
	return value;
};

/**
 * Flattens an array `level` times.
 * @memberOf array
 * @function
 * @returns {Array} The flattened array.
 * @example
 * console.log(_$.flatten(['a', 'b', ['c', 'd']])); // ['a', 'b', 'c', 'd'];
 * @param {Array} array The array to flatten.
 * @param {Number} [level=1] The number of iterations to flatten it.
 */
export let flatten = (array = req("array", "array"), level = 1) => {
	var output = array;
	_$.each(level, () => {
		output = [].concat.apply([], array);
	});
	return output;
};

/**
 * Flattens an array recursively.
 * @function
 * @memberOf array
 * @param {Array} arr The array to flatten.
 * @returns {Array} The flattened array.
 * @example
 * console.log(_$.nFlatten([5,[[9,4],0],[7,6]])); // [5,9,4,0,6,7]
 */
export let nFlatten = (arr = req("array", "array")) => {
	return arr.reduce(function (flat, toFlatten) {
		return flat.concat(
			Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten,
		);
	}, []);
};

/**
 * Returns whether the specified array or string contains the item given.
 * @memberOf array
 * @function
 * @param {Array} array The array to test with.
 * @param {String} item The item to see if the array contains.
 * @example
 * console.log(_$.contains([1,2,3,4,5], 3)); // true
 * @returns {Boolean} True or false depending on if the array contains that item.
 */
export let contains = (array = req("array"), item = req("string")) =>
	array.includes(item);

/**
 * Shuffles an array
 * @function
 * @memberOf array
 * @param {Array} array The array to shuffle.
 * @example
 * let array = [1,2,3,4,5];
 * console.log(_$.shuffleArray(array)); // e.g. [2,4,1,5,3]
 * @returns {Array} The shuffled array.
 */
export let shuffleArray = (array = req("array")) =>
	array.sort(() => Math.random() - 0.5);

/**
 * Splice but also for strings
 * @memberOf array
 * @function
 * @param {String|Array} array The array or string to operate on
 * @param {Number} index The index to splice
 * @param {*} item The item
 * @param {Number} [remove=0] How many to remove.
 * @returns {String|Array} the spliced array or string
 * @example
 * console.log(_$.splice("hello earthlings", 5, " puny")); // "hello puny earthlings"
 */
export let splice = (
	array = req("array", "array"),
	index = req("number", "index"),
	remove = 0,
	item,
) => {
	let args = Array.from(arguments);
	args.shift();
	return typeof array === "string"
		? array
				.split("")
				.splice(...args)
				.join("")
		: array.splice(...args);
};
/**
 * Joins two arrays together and removes duplicate items.
 * @function
 * @memberOf array
 * @param {Array} x The first array to join.
 * @param {Array} y The second array to join.
 * @example
 * console.log(_$.unionArrays([1,2,3,4], [4,5,6])); // [1,2,3,4,5,6]
 * @returns {Array} The joined array from the two other arrays.
 */
export let unionArrays = (
	x = req("array", "array1"),
	y = req("array", "array2"),
) => {
	var obj = {};
	for (var i = x.length - 1; i >= 0; --i) obj[x[i]] = x[i];
	for (var i = y.length - 1; i >= 0; --i) obj[y[i]] = y[i];
	var res = [];
	for (var k in obj) {
		if (obj.hasOwnProperty(k)) res.push(obj[k]);
	}
	return res;
};
/**
 * @callback averageByFn
 * @param {Number} number The number to perform the operation on
 * @returns {Number} The number to average
 */
/**
 * averageBy
 * @function
 * @memberOf array
 * @param {Array.<number>} arr The array to average
 * @param {averageByFn} fn The function to apply to each item of the array.
 * @example
 * Logs the average of the first 4 square numbers:
 * console.log(_$.averageBy([1,2,3,4], (v) => v ** 2)); // 7.5
 * @returns {Number} The average of the array.
 */
export let averageBy = (
	arr = req("array", "array"),
	fn = req("function", "callback"),
) =>
	arr
		.map(typeof fn === "function" ? fn : (val) => val[fn])
		.reduce((acc, val) => acc + val, 0) / arr.length;

/**
 * Removes duplicates from an array
 * @function
 * @memberOf array
 * @param {Array} array The array to remove duplicates from.
 * @example
 * console.log(_$.uniqueArray([1,1,2,3,4,4,4,5,6)); // [1,2,3,4,5,6]
 * @returns {Array} The array with no duplicates.
 */
export let uniqueArray = (array = req("array", "array")) => [
	...new Set(array),
];
/**
 * @callback eachCallback
 * @param {any} x The item of the array/string/number range
 * @param {Number} i The index of the item in the array/string/number range
 * @param {any[]} array The original array
 */
/**
 * For each item in an array, run a callback with it.
 * @function
 * @memberOf array
 * @param {Array|String|Number} array The array, string or number to run the callback with.
 * @param {eachCallback} callback The callback function to run on the array items.
 * @example
 * _$.each(new Array(6), (array_item, i) => console.log(i));
 * // 0
 * // 1
 * // 2
 * // 3
 * // 4
 * // 5
 * @returns {any[]} The array passed at the beginning.
 */
export let each = (
	array = req("Array|Number|String", "array"),
	callback = req("function", "callback"),
) => {
	array =
		typeof array === "number"
			? _$.range(1, array)
			: typeof array === "string"
			? array.split("")
			: array;
	for (let i = 0; i < array.length; i++) {
		callback(array[i], i, array);
	}
	return array;
};
//#endregion Array