Add count optional argument to Collection methods (#1552)

* Add `count` optional argument to Collection methods

[NON-BREAKING CHANGE]
An optional `count` argument is added to the following methods:
- random() and randomKey()
- first() and firstKey()
- last() and lastKey()

If `count` is used, the method returns an array instead of only the value. Performance impact non-existent for existing code. Performance for returning an array has been measured and this is the fastest I could find (array[i] = value is faster than array.push()).

* Update Collection.js

Fixed spacing/line length errors according to suggestions by codacy/pr

* Fixed docs

Added proper `@returns {*|Array}` as the methods might return either. Also added params where missing (whoops)

* Further doc fixes

Per Crawl's comments, fixed (i + 1) spacing as well as fixed {Integer} to {number}

* random() and randomKey() fix

Per Hydra's comment, random() and randomKey() now ensures unique values.
I've also resolved potential issues with requesting a count higher than the collection size. A collection with 10 items will only ever return at most 10 items using the `count` property.

* Can I facepalm harder

Had wrong header comments ^_^

* Fixed for "values/value" and Omited

Also, added "Positive" integer check.

* looks like I "omitted" a change, there.

* Update Collection.js

* Update Collection.js

* Update Collection.js
This commit is contained in:
Évelyne Lachance
2017-06-07 18:52:41 -04:00
committed by Crawl
parent 7aa791eaaa
commit d513c4bbb9

View File

@@ -59,59 +59,99 @@ class Collection extends Map {
}
/**
* Obtains the first item in this collection.
* @returns {*}
* Obtains the first value(s) in this collection.
* @param {number} [count] Number of values to obtain from the beginning
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
*/
first() {
return this.values().next().value;
first(count) {
if (count === undefined) return this.values().next().value;
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
count = Math.min(this.size, count);
const arr = new Array(count);
const iter = this.values();
for (let i = 0; i < count; i++) arr[i] = iter.next().value;
return arr;
}
/**
* Obtains the first key in this collection.
* @returns {*}
* Obtains the first key(s) in this collection.
* @param {number} [count] Number of keys to obtain from the beginning
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
*/
firstKey() {
return this.keys().next().value;
firstKey(count) {
if (count === undefined) return this.keys().next().value;
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
count = Math.min(this.size, count);
const arr = new Array(count);
const iter = this.iter();
for (let i = 0; i < count; i++) arr[i] = iter.next().value;
return arr;
}
/**
* Obtains the last item in this collection. This relies on the `array()` method, and thus the caching mechanism
* applies here as well.
* @returns {*}
* Obtains the last value(s) in this collection. This relies on {@link Collection#array}, and thus the caching
* mechanism applies here as well.
* @param {number} [count] Number of values to obtain from the end
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
*/
last() {
last(count) {
const arr = this.array();
return arr[arr.length - 1];
if (count === undefined) return arr[arr.length - 1];
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
return arr.slice(-count);
}
/**
* Obtains the last key in this collection. This relies on the `keyArray()` method, and thus the caching mechanism
* applies here as well.
* @returns {*}
* Obtains the last key(s) in this collection. This relies on {@link Collection#keyArray}, and thus the caching
* mechanism applies here as well.
* @param {number} [count] Number of keys to obtain from the end
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
*/
lastKey() {
lastKey(count) {
const arr = this.keyArray();
return arr[arr.length - 1];
if (count === undefined) return arr[arr.length - 1];
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
return arr.slice(-count);
}
/**
* Obtains a random item from this collection. This relies on the `array()` method, and thus the caching mechanism
* applies here as well.
* @returns {*}
* Obtains random value(s) from this collection. This relies on {@link Collection#array}, and thus the caching
* mechanism applies here as well.
* @param {number} [count] Number of values to obtain randomly
* @returns {*|Array<*>} The single value if `count` is undefined, or an array of values of `count` length
*/
random() {
const arr = this.array();
return arr[Math.floor(Math.random() * arr.length)];
random(count) {
let arr = this.array();
if (count === undefined) return arr[Math.floor(Math.random() * arr.length)];
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
if (arr.length === 0) return [];
const rand = new Array(count);
arr = arr.slice();
for (let i = 0; i < count; i++) rand[i] = arr.splice(Math.floor(Math.random() * arr.length), 1)[0];
return rand;
}
/**
* Obtains a random key from this collection. This relies on the `keyArray()` method, and thus the caching mechanism
* applies here as well.
* @returns {*}
* Obtains random key(s) from this collection. This relies on {@link Collection#keyArray}, and thus the caching
* mechanism applies here as well.
* @param {number} [count] Number of keys to obtain randomly
* @returns {*|Array<*>} The single key if `count` is undefined, or an array of keys of `count` length
*/
randomKey() {
const arr = this.keyArray();
return arr[Math.floor(Math.random() * arr.length)];
randomKey(count) {
let arr = this.keyArray();
if (count === undefined) return arr[Math.floor(Math.random() * arr.length)];
if (typeof count !== 'number') throw new TypeError('The count must be a number.');
if (!Number.isInteger(count) || count < 1) throw new RangeError('The count must be an integer greater than 0.');
if (arr.length === 0) return [];
const rand = new Array(count);
arr = arr.slice();
for (let i = 0; i < count; i++) rand[i] = arr.splice(Math.floor(Math.random() * arr.length), 1)[0];
return rand;
}
/**