/**
* @module MelLinq
*/
import { isArrayLike } from '../mel.js';
export { MelEnumerable, MelKeyValuePair };
/**
* @callback WhereCallback
* @param {*} item
* @param {number} index
* @returns {Boolean}
*/
/**
* @callback SelectCallback
* @param {*} item
* @param {number} index
* @returns {*}
*/
/**
* @callback SelectorCallback
* @param {*} item
* @returns {*}
*/
/**
* @class
* @classdesc Représentation d'un valeur et de sa clé
*/
class MelKeyValuePair {
/**
*
* @param {!string | !number} key Clé qui est lié à la valeur
* @param {*} value Valeur
*/
constructor(key, value) {
let _key = key;
let _value = value;
/**
* Clé qui est lié à la valeur
* @type {!string | !number}
* @readonly
*/
this.key;
/**
* Valeur qui est lié à une clé
* @type {*}
* @readonly
*/
this.value;
Object.defineProperties(this, {
key: {
get: () => {
return _key;
},
configurable: false,
},
value: {
get: () => {
return _value;
},
configurable: false,
},
});
}
}
class RotomecaGenerator {
constructor(iterable) {
this.iterable = iterable;
}
*[Symbol.iterator]() {
for (const iterator of this.next()) {
yield iterator;
}
}
where(callback) {
return new RotomecaWhereGenerator(this, callback);
}
select(callback) {
return new RotomecaSelectGenerator(this, callback);
}
groupBy(key_selector, value_selector = null) {
return new RotomecaGroupByGenerator(this, key_selector, value_selector);
}
orderBy(selector) {
return new RotomecaOrderGenerator(this, selector);
}
orderByDescending(selector) {
return new RotomecaOrderByDesendingGenerator(this, selector);
}
then(selector) {
return new RotomecaThenGenerator(this, selector);
}
thenDescending(selector) {
return new RotomecaThenDescendingGenerator(this, selector);
}
reverse() {
return new RotomecaReverseGenerator(this);
}
take(howMany) {
return new RotomecaTakeGenerator(this, howMany);
}
add(item) {
return this.aggregate(item);
}
aggregate(iterable) {
return new RotomecaAggegateGenerator(this, iterable);
}
remove(item) {
return new RotomecaRemoveGenerator(this, item);
}
removeAt(index) {
return new RotomecaRemoveAtIndexGenerator(this, index);
}
distinct(selector = null) {
return new RotomecaDistinctGenerator(this, selector);
}
except(array) {
return new RotomecaExceptGenerator(this, array);
}
intersect(array) {
return new RotomecaIntersectGenerator(this, array);
}
union(array, c = null) {
return new RotomecaUnionGenerator(this, array, c);
}
any(callback = null) {
let it = 0;
for (const iterator of this) {
if (!callback) return true;
else if (callback(iterator, it++)) return true;
}
return false;
}
all(callback = null) {
return !this.any((value, index) => {
return !callback(value, index);
});
}
contains(item) {
return this.any((value, index) => {
return value === item;
});
}
first(callback = null) {
const not_exist = Symbol();
const value = this.firstOrDefault(not_exist, callback);
if (value === not_exist) throw 'Item not exist';
else return value;
}
firstOrDefault(default_value = null, callback = null) {
let generator = callback ? this.where(callback) : this;
for (const iterator of generator) {
return iterator;
}
return default_value;
}
last(where = null) {
const not_exist = Symbol();
const value = this.lastOrDefault({ default_value: not_exist, where });
if (value === not_exist) throw 'Item not exist';
else return value;
}
lastOrDefault({ default_value = null, where = null }) {
let generator = this;
if (where) generator = generator.where(where);
let last = default_value;
for (const iterator of generator) {
last = iterator;
}
return last;
}
flat() {
return new RotomecaFlatGenerator(this);
}
*next() {
let iterable;
if (typeof this.iterable === 'function' && !!this.iterable.prototype.next)
iterable = this.iterable();
else iterable = this.iterable;
for (const iterator of iterable) {
yield iterator;
}
}
count() {
if (!this.length) {
this.length = 0;
for (const iterator of this) {
++this.length;
}
}
return this.length;
}
join(separator = '') {
return this.toArray().join(separator);
}
sum({ where = null, selector = null }) {
let generator = this;
if (where) generator = generator.where(where);
if (selector) generator = generator.select(selector);
let sum = 0;
for (const iterator of generator) {
sum += iterator;
}
return sum;
}
_findMinMax() {
let array = this.toArray();
const length = array.length;
let max, min, i;
if (length % 2 !== 0) {
max = array[0];
min = array[0];
i = 1;
} else {
if (array[0] >= array[1]) {
max = array[0];
min = array[1];
} else {
max = array[1];
min = array[0];
}
i = 2;
}
while (i < length) {
if (array[i] < array[i + 1]) {
if (array[i] < min) min = array[i];
if (array[i + 1] > max) max = array[i + 1];
} else {
if (array[i + 1] < min) min = array[i + 1];
if (array[i] > max) max = array[i];
}
i += 2;
}
return { min, max };
}
max(selector = null) {
let generator = selector ? this.select(selector) : this;
return generator._findMinMax().max;
}
min(selector = null) {
let generator = selector ? this.select(selector) : this;
return generator._findMinMax().min;
}
toArray() {
let arr = [];
for (const iterator of this) {
arr.push(iterator);
}
return arr;
}
toJsonObject(key_selector, value_selector) {
let i = 0;
let obj = {};
for (const iterator of this) {
obj[key_selector(iterator, i)] = value_selector(iterator, i);
++i;
}
return obj;
}
}
class ARotomecaCallbackGenerator extends RotomecaGenerator {
constructor(iterable, callback) {
super(iterable);
this.callback = callback;
}
}
class RotomecaWhereGenerator extends ARotomecaCallbackGenerator {
constructor(iterable, callback) {
super(iterable, callback);
}
*next() {
let star_parent = super.next();
let i = 0;
for (const iterator of star_parent) {
if (this.callback(iterator, i++)) yield iterator;
}
}
}
class RotomecaSelectGenerator extends ARotomecaCallbackGenerator {
constructor(iterable, callback) {
super(iterable, callback);
}
*next() {
let star_parent = super.next();
let i = 0;
for (const iterator of star_parent) {
yield this.callback(iterator, i++);
}
}
}
class ARotomecaKeyValueSelector extends ARotomecaCallbackGenerator {
constructor(iterable, key_selector, value_selector = null) {
super(iterable, value_selector);
this.key_selector = key_selector;
}
}
class RotomecaGroupedItems {
constructor(key, iterable) {
this.iterable = iterable;
this.key = key;
}
*next() {
let star_parent = this.iterable;
for (const iterator of star_parent) {
yield new MelKeyValuePair(this.key, iterator);
}
}
get_values(try_get_array = true) {
if (try_get_array && this.iterable instanceof MelEnumerable) {
if (Array.isArray(this.iterable.generator()))
return this.iterable.generator();
else if (
this.iterable.generator() instanceof RotomecaGenerator &&
Array.isArray(this.iterable.generator().iterable)
)
return this.iterable.generator().iterable;
}
return this.iterable;
}
}
class RotomecaGroupByGenerator extends ARotomecaKeyValueSelector {
constructor(iterable, key_selector, value_selector = null) {
super(iterable, key_selector, value_selector);
}
*next() {
let star_parent = super.next();
let key;
let datas = {};
for (const item of star_parent) {
key = this.key_selector(item);
if (!datas[key]) datas[key] = [];
datas[key].push(this.callback ? this.callback(item) : item);
}
for (const key in datas) {
if (Object.hasOwnProperty.call(datas, key)) {
const element = datas[key];
yield new RotomecaGroupedItems(key, MelEnumerable.from(element));
}
}
}
}
class ARotomecaOrderGenerator extends ARotomecaCallbackGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
sort(a, b) {
return 0;
}
*next() {
let star_parent = super.next();
let array = [];
for (const iterator of star_parent) {
array.push(iterator);
}
array = array.sort((a, b) => {
return this.sort(a, b);
});
for (const iterator of array) {
yield iterator;
}
array = null;
}
}
class RotomecaOrderGenerator extends ARotomecaOrderGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
sort(a, b) {
super.sort(a, b);
a = this.callback(a);
b = this.callback(b);
if (a > b) return 1;
else if (b > a) return -1;
return 0;
}
}
class RotomecaOrderByDesendingGenerator extends RotomecaOrderGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
sort(a, b) {
return -super.sort(a, b);
}
}
class RotomecaThenGenerator extends ARotomecaOrderGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
sort(a, b) {
super.sort(a, b);
if (a === b) {
a = this.callback(a);
b = this.callback(b);
if (a > b) return 1;
else if (b > a) return -1;
}
return 0;
}
}
class RotomecaThenDescendingGenerator extends RotomecaThenGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
sort(a, b) {
return -super.sort(a, b);
}
}
class ARotomecaItemModifierGenerator extends RotomecaGenerator {
constructor(iterable, item) {
super(iterable);
this.item = item;
}
*next() {
yield* super.next();
}
}
class RotomecaAggegateGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, item) {
super(iterable, item);
}
*next() {
let star_parent = super.next();
for (const iterator of star_parent) {
yield iterator;
}
if (
Array.isArray(this.item) ||
typeof this.item[Symbol.iterator] === 'function'
) {
for (const iterator of this.item) {
yield iterator;
}
} else if (typeof this.item === 'function' && !!this.item.prototype.next) {
for (const iterator of this.item()) {
yield iterator;
}
} else yield this.item;
}
}
class ARotomecaRemoverGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, item) {
super(iterable, item);
}
*next() {
let star_parent = super.next();
this.before();
for (const iterator of star_parent) {
if (this.compare(iterator) !== this.item) yield iterator;
}
this.after();
}
compare(item) {
return item;
}
before() {}
after() {}
}
class RotomecaRemoveGenerator extends ARotomecaRemoverGenerator {
constructor(iterable, item) {
super(iterable, item);
}
}
class RotomecaRemoveAtIndexGenerator extends ARotomecaRemoverGenerator {
constructor(iterable, item) {
super(iterable, item);
this.it = 0;
}
compare(item) {
super.compare(item);
return this.it++;
}
before() {
super.before();
this.it = 0;
}
}
class RotomecaFlatGenerator extends RotomecaGenerator {
constructor(iterable) {
super(iterable);
}
*next() {
let star_parent = super.next();
for (const iterator of star_parent) {
yield* this.generate(iterator);
}
}
*generate(iterator) {
if (this.check(iterator)) {
for (const item of iterator) {
if (this.check(item)) {
yield* this.generate(item);
} else yield item;
}
} else yield iterator;
}
check(iterator) {
return (
typeof iterator !== 'string' &&
(Array.isArray(iterator) ||
isArrayLike(iterator) ||
typeof iterator[Symbol.iterator] === 'function')
);
}
}
//TO ADD
class RotomecaDistinctGenerator extends ARotomecaCallbackGenerator {
constructor(iterable, selector) {
super(iterable, selector);
}
*next() {
let star_parent = super.next();
let things = [];
const have_selector = !!this.callback;
let item;
for (const iterator of star_parent) {
item = have_selector ? this.callback(iterator) : iterator;
if (!things.includes(item)) {
yield item;
things.push(item);
}
}
things = null;
}
}
//TO ADD
class RotomecaExceptGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, array) {
super(iterable, MelEnumerable.from(array).generator());
}
*next() {
let star_parent = super.next();
for (const iterator of star_parent) {
if (!this.item.contains(iterator)) {
yield iterator;
}
}
}
}
class RotomecaUnionGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, array, callback = null) {
super(iterable, array);
this.callback = callback;
this.things = [];
this.current = null;
}
*next() {
let star_parent = super.next();
const have_selector = !!this.callback;
this.things = [];
this.current = null;
yield* this.generate(have_selector, star_parent);
yield* this.generate(have_selector, this.item);
this.things = [];
this.current = null;
}
*generate(have_selector, generator) {
for (const iterator of generator) {
this.current = have_selector ? this.callback(iterator) : iterator;
if (!this.things.includes(this.current)) {
yield this.current;
this.things.push(this.current);
}
}
}
}
class RotomecaIntersectGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, array) {
super(iterable, array);
}
*next() {
let star_parent = super.next();
for (const iterator of star_parent) {
if (this.item.contains(iterator)) {
yield iterator;
}
}
}
}
class RotomecaReverseGenerator extends RotomecaGenerator {
constructor(iterable) {
super(iterable); //RotomecaOrderByDesendingGenerator
}
*next() {
let order = MelEnumerable.from(super.next()).toArray();
for (let len = order.length, index = len - 1; index >= 0; --index) {
yield order[index];
}
}
}
class RotomecaTakeGenerator extends ARotomecaItemModifierGenerator {
constructor(iterable, number) {
super(iterable, number);
}
*next() {
let p = super.next();
let it = 0;
for (const iterator of p) {
yield iterator;
if (++it === this.item) break;
}
it = null;
}
}
class ObjectKeyEnumerable extends RotomecaGenerator {
constructor(object) {
super();
this.iterable = MelEnumerable.from(this._generate.bind(this, object));
}
*_generate(object) {
for (const key in object) {
if (Object.hasOwnProperty.call(object, key)) {
const element = object[key];
yield new MelKeyValuePair(key, element);
}
}
}
}
/**
* @callback RGenerator
* @returns {MelEnumerable}
*/
/**
* Classe principale des enumerations.
*
* Permet d'avoir un comportement semblable à System.Linq du C#
* @class
* @see {@link https://docs.microsoft.com/en-us/dotnet/api/system.linq}
* @hideconstructor
*/
class MelEnumerable {
/**
* @param {Generator | Array | MelEnumerable | RotomecaGenerator | JSON} generator
*/
constructor(generator) {
let _generator = generator;
/**
* Récupère le générateur.
* @readonly
* @type {RGenerator}
*/
this.generator = undefined;
Object.defineProperty(this, 'generator', {
enumerable: false,
configurable: false,
writable: false,
value: function () {
return _generator;
},
});
}
/**
* Récupère que les éléments dont callback retourne "vrai"
* @param {WhereCallback} callback Fonction qui servira à tester les éléments
* @generator
* @returns {MelEnumerable}
*/
where(callback) {
return new MelEnumerable(this.generator().where(callback));
}
/**
* Sélectionne une donnée à partir des éléments de l'énumération
* @param {SelectCallback} selector
* @generator
* @returns {MelEnumerable}
*/
select(selector) {
return new MelEnumerable(this.generator().select(selector));
}
/**
* Groupe les données par clé et par valeur.
* @param {SelectorCallback} key_selector Génère les différentes clés
* @param {?SelectorCallback} value_selector Génère les différentes valeurs, l'élément entier est pris si null
* @returns {MelEnumerable}
* @generator
*/
groupBy(key_selector, value_selector = null) {
return new MelEnumerable(
this.generator().groupBy(key_selector, value_selector),
);
}
/**
* Tri les données (croissant)
* @param {SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
orderBy(selector) {
return new MelEnumerable(this.generator().orderBy(selector));
}
/**
* Tri les données (décroissant)
* @param {SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
orderByDescending(selector) {
return new MelEnumerable(this.generator().orderByDescending(selector));
}
/**
* Tri les données (croissant), à utiliser après orderBy
* @param {SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
then(selector) {
return new MelEnumerable(this.generator().then(selector));
}
/**
* Tri les données (décroissant), à utiliser après orderBy
* @param {SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
thenDescending(selector) {
return new MelEnumerable(this.generator().thenDescending(selector));
}
/**
* Ajoute un objet à l'énumération
* @param {*} item
* @returns {MelEnumerable}
* @generator
*/
add(item) {
return new MelEnumerable(this.generator().add(item));
}
/**
* Ajoute un itérable à l'énumération
* @param {Array | Generator} iterable
* @returns {MelEnumerable}
* @generator
*/
aggregate(iterable) {
return new MelEnumerable(this.generator().aggregate(iterable));
}
/**
* Supprime un objet à l'énumération si il est présent
* @param {*} item
* @returns {MelEnumerable}
* @generator
*/
remove(item) {
return new MelEnumerable(this.generator().remove(item));
}
/**
* Supprime un objet à un index de l'énumération si il est présent
* @param {number} index
* @returns {MelEnumerable}
* @generator
*/
removeAt(index) {
return new MelEnumerable(this.generator().removeAt(index));
}
/**
* Empèche d'avoir 2 valeurs identiques dans l'énumération
* @param {?SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
distinct(selector = null) {
return new MelEnumerable(this.generator().distinct(selector));
}
/**
* Empèche d'avoir les valeurs du tableau dans l'énumération
* @param {any[] | Generator} array
* @returns {MelEnumerable}
* @generator
*/
except(array) {
return new MelEnumerable(this.generator().except(array));
}
/**
* Empèche d'avoir les valeurs en commun du tableau dans l'énumération
* @param {any[] | Generator} array
* @returns {MelEnumerable}
* @generator
*/
intersect(array) {
return new MelEnumerable(this.generator().intersect(array));
}
/**
* Fusionne les 2 tableaux
* @param {any[] | Generator} array
* @param {?SelectorCallback} selector
* @returns {MelEnumerable}
* @generator
*/
union(array, selector = null) {
return new MelEnumerable(this.generator().union(array, selector));
}
/**
* Renvoie l'énumération à l'envers
* @returns {MelEnumerable}
* @generator
*/
reverse() {
return new MelEnumerable(this.generator().reverse());
}
/**
* Prend les x premiers éléments
* @param {number} howMany x premiers éléments à prendre
* @returns {MelEnumerable}
* @generator
*/
take(howMany) {
return new MelEnumerable(this.generator().take(howMany));
}
/**
* Retourne vrai si il y a au moins un élément dans l'énumération.
* @param {?WhereCallback} callback Si défini, éffectue un `where` avant de faire le any.
* @returns {boolean}
* @see {@link MelEnumerable~where}
*/
any(callback = null) {
return this.generator().any(callback);
}
/**
* Retourne vrai si tout les éléments existent dans l'énumération.
* @param {?WhereCallback} callback Si défini, éffectue un `where` avant de faire le all.
* @returns {boolean}
* @see {@link MelEnumerable~where}
*/
all(callback = null) {
return this.generator().all(callback);
}
/**
* Retourne vrai si l'élément existe dans l'énumération.
* @param {*} item
* @returns {boolean}
*/
contains(item) {
return this.generator().contains(item);
}
/**
* Retourne le premier élément dans l'énumération.
* @param {?WhereCallback} callback Si défini, éffectue un `where` avant de faire le first.
* @returns {*}
* @throws If null
*/
first(callback = null) {
return this.generator().first(callback);
}
/**
* Retourne le premier élément dans l'énumération.
* @param {?any} default_value Valeur par défaut si on ne trouve rien
* @param {?WhereCallback} callback Si défini, éffectue un `where` avant de faire le firstOrDefault.
* @returns {*}
*/
firstOrDefault(default_value = null, callback = null) {
return this.generator().firstOrDefault(default_value, callback);
}
/**
* La fonction `last` renvoie le dernier élément d'un générateur, éventuellement filtré par une
* condition.
* @param {?WhereCallback} where - Le paramètre "where" est une fonction qui détermine si un élément doit être
* inclus ou non dans la recherche. Il permet de filtrer les éléments avant de retrouver le dernier. Si
* la fonction "where" renvoie vrai pour un élément, celui-ci sera inclus dans la recherche ; sinon, ce
* sera
* @returns Le dernier élément du générateur qui satisfait la condition donnée.
*/
last(where = null) {
return this.generator().last(where);
}
/**
* La fonction renvoie le dernier élément d'un générateur ou une valeur par défaut si le générateur est
* vide.
* @param {Object} param0
* @param {?any} [param0.default_value=null] Valeur par défaut si on ne trouve rien
* @param {?WhereCallback} [param0.where=null] Fonction where qui sera appliqué avant de récupérer le dernier élément
* @returns La fonction lastOrDefault renvoie le résultat de l'appel de la fonction lastOrDefault du
* générateur avec les paramètres fournis.
*/
lastOrDefault({ default_value = null, where = null }) {
return this.generator().lastOrDefault({ default_value, where });
}
/**
* Si il y a des tableaux dans les tableaux, transforme tout en un seul tableau
* @returns {MelEnumerable}
* @generator
*/
flat() {
return new MelEnumerable(this.generator().flat());
}
*[Symbol.iterator]() {
for (const iterator of this.generator()) {
yield iterator;
}
}
/**
* Change l'énumération en chaîne de charactères
* @param {string} separator
* @returns {string}
*/
join(separator = '') {
return this.generator().join(separator);
}
/**
* Fait la somme des éléments de l'énumération
* @param {Object} param0 Si défini, le `where` sera pris en compte avant le `select`
* @param {?WhereCallback} where Prendre seulement ce qui nous intéresse dans le sum
* @param {?SelectCallback} selector Séléctionner le membre sur lequel on veut faire un sum
* @returns {number}
* @throws Si selector retourne autre chose qu'un nombre
* @see {@link WhereCallback}
* @see {@link SelectCallback}
*/
sum({ where = null, selector = null }) {
return this.generator().sum({ where, selector });
}
/**
* Compte le nombre d'éléments dans l'énumération
* @returns {number}
*/
count() {
return this.generator().count();
}
/**
* Récupère la valeur maximale de l'énumération
* @param {?SelectorCallback} selector Séléctionne la valeur à comparer
* @returns {number}
*/
max(selector = null) {
return this.generator().max(selector);
}
/**
* Récupère la valeur minimale de l'énumération
* @param {?SelectorCallback} selector Séléctionne la valeur à comparer
* @returns {number}
*/
min(selector = null) {
return this.generator().min(selector);
}
/**
* Transforme en tableau
* @returns {Array}
*/
toArray() {
return this.generator().toArray();
}
/**
* Convertit en objet
* @param {SelectCallback} key_selector
* @param {SelectCallback} value_selector
* @returns {{}} style {index1:value1 etc....}
*/
toJsonObject(key_selector, value_selector) {
return this.generator().toJsonObject(key_selector, value_selector);
}
/**
* Convertit un objet/un tableau en enumerable
* @generator
* @param {Array | RotomecaGenerator | MelEnumerable | {} | Generator} item Objet à convertir en enumerable
* @returns {MelEnumerable}
*/
static from(item) {
const is_array_like = isArrayLike(item);
if (
Array.isArray(item) ||
(typeof item[Symbol.iterator] === 'function' && !is_array_like)
)
return new MelEnumerable(new RotomecaGenerator(item));
else if (item instanceof RotomecaGenerator) return new MelEnumerable(item);
else if (typeof item === 'object' && !is_array_like) {
return this.from(new ObjectKeyEnumerable(item));
} else if (is_array_like)
return new MelEnumerable(new RotomecaGenerator(Array.from(item)));
else if (typeof item === 'function' && !!item.prototype.next)
return new MelEnumerable(new RotomecaGenerator(item));
else return new MelEnumerable(new RotomecaGenerator([item]));
}
/**
* Récupère des éléments au hasard dans un tableau
* @param {Array | RotomecaGenerator | MelEnumerable | {} | Generator} item
* @param {...any} args Autres objets qui seront pris au hasard
* @returns {MelEnumerable}
* @generator
*/
static choice(item, ...args) {
item = MelEnumerable.from(item)
.aggregate(args || [])
.toArray();
const min = 0;
const max = item.length - 1;
const generator = function* () {
while (true) {
yield item[Math.floor(Math.random() * (max - min + 1) + min)];
}
};
return MelEnumerable.from(generator);
}
/**
* Génère les éléments sous forme d'un cycle.
* @param {Array | RotomecaGenerator | MelEnumerable | {} | Generator} item Initialisateur
* @param {...any} args Initialisateurs
* @returns {MelEnumerable}
* @generator
*/
static cycle(item, ...args) {
item = MelEnumerable.from(item)
.aggregate(args || [])
.toArray();
let it = 0;
const generator = function* () {
while (true) {
yield item[it++];
if (it === item.length) it = 0;
}
};
return MelEnumerable.from(generator);
}
/**
* Génère un énumérable vide
* @returns {MelEnumerable}
* @generator
*/
static empty() {
return MelEnumerable.from([]);
}
/**
* Génère des valeurs commençant par "start", pendant "count" par pas de "step"
*
* (ex: (0,5,2) => [0,2,4,6,8])
* @param {number} start Valeur de départ
* @param {number} count Pendant combien d'itérations ?
* @param {number} step pas
* @returns {MelEnumerable}
* @generator
*/
static range(start, count, step = 1) {
let it = 0;
const generator = function* () {
while (it++ < count) {
yield start;
start += step;
}
};
return MelEnumerable.from(generator);
}
/**
* Génère des valeurs commençant par "start", pendant "count" par pas de "step" (décroissant)
*
* (ex: (0,5,2) => [0, -2, -4, -6, -8])
* @param {number} start Valeur de départ
* @param {number} count Pendant combien d'itérations ?
* @param {number} step pas
* @returns {MelEnumerable}
* @generator
*/
static rangeDown(start, count, step = 1) {
return MelEnumerable.range(start, count, -step);
}
/**
* Génère des valeurs commençant par "start" indéfiniment par pas de "step"
* @param {number} start Valeur de départ
* @param {number} step pas
* @returns {MelEnumerable}
* @generator
*/
static toInfinity(start = 0, step = 1) {
return MelEnumerable.range(start, Number.POSITIVE_INFINITY, step);
}
/**
* Génère des valeurs commençant par "start" indéfiniment par pas de "step" (décroissant)
* @param {number} start Valeur de départ
* @param {number} step pas
* @returns {MelEnumerable}
* @generator
*/
static toNegativeInfinity(start = 0, step = 1) {
return MelEnumerable.toInfinity(start, -step);
}
static generate(callback) {
const generator = function* () {
while (true) {
yield callback();
}
};
return MelEnumerable.from(generator);
}
/**
* Génère des nombres au hasard
* @param {number} min
* @param {number} max
* @returns
* @generator
*/
static random(min = 0, max = 1000) {
return MelEnumerable.generate(() => {
return Math.random() * (max - min + 1) + min;
});
}
static async fromAsync(async_generator) {
let arr = [];
let next;
while ((next = await async_generator.next()) && !next.done) {
arr.push(next.value);
}
return MelEnumerable.from(arr);
}
}