Skip to content

Instantly share code, notes, and snippets.

@yigsvnsla
Created January 13, 2023 08:24
Show Gist options
  • Save yigsvnsla/88bd3f4c1ae2bcc026b1f9ec91a00f28 to your computer and use it in GitHub Desktop.
Save yigsvnsla/88bd3f4c1ae2bcc026b1f9ec91a00f28 to your computer and use it in GitHub Desktop.
Script para generar y manejar estructuras de datos FIFO `First in, First Out` de manera agnostica a los datos insertados a la cola | v0.1
/**
* Script para generar y manejar estructuras de datos FIFO `First in, First Out`
* de manera agnostica a los datos insertados a la cola
* @author Yigsvnsla <https://github.com/yigsvnsla>
* @version 0.1
*/
export class Queue<T extends { [key: string]: any }> {
/**
* @protected Array donde se almaceran los objetos para la cola
*/
protected _queue: T[]
/**
* @protected Posicion del puntero inicial
*/
protected _front: number
/**
* @protected Posicion del puntero final
*/
protected _rear: number
/**
* @protected Longitud de la cola
*/
protected _length: number | undefined;
/**
* inicializar la cola con un tamaño definido, o con valores ya pre-establecidos
* @param { T[]} _arg1 valores inciales
* @example <caption>Ejemplo de uso con un Arreglo pre-establecido.</caption>
* const _data = [...]
* const source = new Queue<any>(_data)
* // Valores insertados a la cola | console.log(source)
*/
constructor(_arg1: T[])
/**
* Inicializar la cola con una longitud especifica, dejando las posiciones vacias
* @param {config} _arg1 Establecer longitud inicial
* @example <caption>Ejemplo de una longitud pre-establecida </caption>
* const source = new Queue<any>({length:10})
* // this._length = 10 | console.log(source)
*/
constructor(_arg1: config)
/**
*
*/
constructor(_arg1: T[] | config) {
// Inicializamos los valores iniciales de la cola
this._queue = []
this._front = 0
this._rear = 0
this._length = 0
// si es un arreglo usa una funcion propia para meter a la cola cada elemento
if (Array.isArray(_arg1)) {
this._length = undefined
this.enqueue('front', _arg1)
}
// en caso contrario si es un objeto de configuracion
// establece los valores del mismo
else if (!Array.isArray(_arg1) && typeof _arg1 == 'object') {
this._length = _arg1.length
this._queue = Array.from({ length: (_arg1.length != null) ? _arg1.length : 0 })
}
}
/**
* @return {T} Obtiene el elemento al principio de la cola sin eliminarlo
*/
public get peek(): T {
return this._queue[this._front]
}
/**
* @returns {T[]} Obtener inmutable de la cola
*/
public get values(): T[] {
return this._queue
}
/**
* @returns {number} Obtener largo de la cola
*/
public get size(): number | undefined {
return this._length
}
/**
* @param {T} _data Meter al final de la cola
*/
private set _rearEnqueue(_data: T) {
this._queue[this._rear] = _data;
this._rear += 1
}
/**
* @param {T} _data Meter al inicio de la cola
*/
private set _frontEnqueue(_data: T) {
this._queue[this._rear] = _data;
this._rear += 1
}
/**
* Retorna el valor del puntero, dejando libre la posicion del la cola sin alterar la longitud
* @returns {T} extrae y elimina el elemento del puntero _front_
*/
private get _frontDequeue(): T {
const data = this._queue[this._front]
delete this._queue[this._front]
this._front += 1
return data
}
/**
* Retorna el valor del puntero, dejando libre la posicion del la cola sin alterar la longitud
* @returns {T} extrae y elimina el elemento del puntero _rear_
*/
private get _rearDequeue(): T {
const data = this._queue[this._rear - 1]
delete this._queue[this._rear - 1]
this._rear -= 1
return data
}
/**
* @returns {T} Obtiene una referencia inmutable del elemento a salir de la cola
*/
public peekByIndex(number: number): T {
return this._queue[number]
}
/**
* Retorna el valor del puntero, dejando libre la posicion del la cola sin alterar la longitud
* @param {number} index posicion del elemento en la cola
* @returns {T} extrae y elimina el elemento del puntero _front_
*/
public dequeueByIndex(index: number): T {
const data = this._queue[index]
delete this._queue[index]
this._rear -= 1
return data
}
/**
* metodo publico que agrega (almacena) un elemento a la cola.
* @param {T} data Valores a meter a la cola
* @param {'rear' | 'front'} position posicion de desde la cual meter los elementos
* @throws ``Cola Llena`` intento de desbordamiento
* @example <caption>Importante ingresar en que posicion meter los elementos a la cola </caption>
* source.enqueue('rear', {id: 12,attributes: {} } )
*/
public enqueue(position: 'rear' | 'front', data: T): void
/**
* metodo publico que agrega (almacena) un elemento a la cola.
* @param {T[]} data Valores a meter a la cola
* @param {'rear' | 'front'} position posicion de desde la cual meter los elementos
* @throws ``Cola Llena`` intento de desbordamiento
* @example <caption>Importante ingresar en que posicion meter los elementos a la cola </caption>
* const newData: T[] = [{id: 12,attributes: {} }, ...[] ]
* source.enqueue('rear', newData )
*/
public enqueue(position: 'rear' | 'front', data: T[]): void
/**
*
*/
public enqueue(position: 'rear' | 'front', data: T | T[]): void {
try {
if (this.isfull()) throw new Error(`<enqueue> Cola llena, intento de desbordamiento \n <value> ${data}`);
if (position == 'front') {
if (Array.isArray(data)) { data.forEach((value) => this._frontEnqueue = value); return }
if (!Array.isArray(data)) { this._frontEnqueue = data; return }
}
if (position == 'rear') {
if (Array.isArray(data)) { data.forEach((value) => this._rearEnqueue = value); return }
if (!Array.isArray(data)) { this._rearEnqueue = data; return }
}
} catch (error) {
console.log(error);
}
}
/**
* metodo publico que agrega (almacena) un elemento a la cola.
* @param {number} _cant Cantidad de elementos a eliminar
* @param {'rear' | 'front'} position posicion de desde la cual sacar los elementos
* @returns {T | T[] |null} Retorna un Arreglo de los elementos eliminados sin modificar la longitud de la cola
* @throws ``Cola Vacia`` intento de sub-desbordamiento
* @example <caption>Importante ingresar en que posicion meter los elementos a la cola </caption>
* source.enqueue('rear', 5 )
*/
public dequeue(position: 'rear' | 'front', _cant: number = 0): T | T[] | null {
try {
if (this.isempty()) throw new Error(`<enqueue> Cola Vacia, intento de subDesbordamiento`);
if (_cant < 0) throw new Error("cantidad de posiciones invalidas ( solo numeros positivos )");
if (position == 'front') {
if (_cant > 0) { return Array.from({ length: _cant }).map(value => this._frontDequeue) }
if (_cant == 0) { return this._frontDequeue }
}
if (position == 'rear') {
if (_cant > 0) { return Array.from({ length: _cant }).map(value => this._rearDequeue) }
if (_cant == 0) { return this._rearDequeue }
}
} catch (error) {
console.log(error);
}
return null
}
/**
* @returns {boolean} comprueba si la cola está llena.
*/
public isfull(): boolean {
if (this._length == null) return false;
if (this._length != null) return (this._rear == this._length);
return false
}
/**
* @returns {boolean} comprueba si la cola está vacía.
*/
public isempty(): boolean {
return ((this._rear <= 0))
}
/**
* Actualiza los valores de una posicion de la cola mediante su indice
* @param {number} index Posicion del elemento en la cola
* @param {T} value Vaalor a actualizar en el elemento
*/
public updateByIndex(index: number, value: T) {
if (index >= 0 && index <= this._queue.length) {
this._queue[index] = value
}
else console.error('error upddatebyIndex')
}
/**
* Funcion para actualizar
* todas las propiedades que coincidan con el escalón del objeto
* segun los indices del array
* @param {Array<string>} _arrKeys Niveles de los escalones
* @param {{[key:string:any]}} updateValue Valor a actualizar
* @example <caption>Actualizar los elementos a la cola con un arreglo</caption>
* const source = new Queue()
* ...
* const newData: T[] = [{id: 12,attributes: {} }, ...[] ]
* source.updateByFind(['attributes','name'], newData )
*/
public updateByFind(_arrKeys: string[], updateValue: { [key: string]: any }): void
/**
* Funcion para actualizar
* todas las propiedades que coincidan con el objeto
* @param {{[key:string]:any}} _objectReference Objeto de referencia
* @param {{[key:string]:any}} updateValue Valor a actualizar
* @example <caption>Actualizar los elementos a la cola con un arreglo</caption>
* const source = new Queue()
* ...
* const reference: T = {id: 12,attributes: {...} }
* const newData: any = { dato1,dato2:{ dato2_1, dato2_2}, {...} }
* source.updateByFind(reference, newData )
*/
public updateByFind(_objectReference: { [key: string]: any }, updateValue: { [key: string]: any }): void
/**
*
*/
public updateByFind(_arg1: string[] | { [key: string]: any }, updateValue: { [key: string]: any }): void {
try {
/**
* Función recursiva para filtrar y devolver elementos
* cuyas propiedades hagan match con la llave (Key) asignada como argumento
* @param {string} key Llave con la que hacer match
* @param {any[]} arr Arreglo de objetos a filtrar
* @returns {any[]} Retorna un arreglo de referencias filtradas para hacer match con la _key_
*/
const findToArray = (key: string, arr: any[]): any[] => {
//creamos una lista de referencias
let returned: any[] = [];
// iteramos sobre el argumento a filtrar
for (let index = 0; index < arr.length; index++) {
const element = arr[index];
// si este elemento existe returna un objeto
// con el indice y el valor de esta posicion de la cola
if (element.hasOwnProperty.call(element.value, key)) {
returned.push({ index: element.index, value: element.value[key] })
}
}
return returned;
}
/**
* Funcion recursiva para comparar objetos de manera profunda en sus propiedades
* @param {{[key:string]:any}} objet_base Objeto con la cual tener una referencia
* @param {{[key:string]:any}} objet_compare Objeto con la cual comparar segun la referencia
* @returns {boolean} si encuentra una coincidencia en las propiedades retorna `true`, en caso contrario `false`
*/
const compareObjets = (objet_base: { [key: string]: any }, objet_compare: { [key: string]: any }): boolean => {
for (let [key, val] of Object.entries(objet_base)) {
// si esta propiedad existe
if (objet_compare.hasOwnProperty(key)) {
// si el valor de la llave en el objeto comparador es diferente
if (objet_compare[key] !== val) {
// si el valor de la llave es de tipo objeto,
// aplicar recursividad a la funcion, asi hacemos un sondeo profundo a las propiedades
if (typeof objet_compare[key] == 'object') {
return compareObjets(objet_compare[key], val)
}
// Propiedad ${key}: El valor ${objet_compare[key]} no es equivalente a ${val}
return false;
}
}
// esta propiedad no existe en el objeto comparador;
else return false;
}
return true
}
// si el argumento es un arreglo, busca todos los elementos de la cola que tengan como propiedades
// las mismas keys asignadas en el argumento __arg1_ y actualiza su valor a los establecidos en el argumento _updateValue_
if (Array.isArray(_arg1)) {
// creamos un diccionario de referencias
let matchList: { [key: string]: any }[] = []
// volcamos el diccionario las referencias
for (let _indexQueue = 0; _indexQueue < this._queue.length; _indexQueue++) {
const value = this._queue[_indexQueue];
const index = _indexQueue;
matchList.push({ index, value })
}
// iteramos sobre el argumento pasandole como parametro
// a la funcion `findToArray` el valor de la posicion del arreglo _(Key)_
// y segun lo que retorne dicha funcion se actualiza el diccionario de referencias
for (let _indexArg1 = 0; _indexArg1 < _arg1.length; _indexArg1++) {
const key = _arg1[_indexArg1];
matchList = findToArray(key, matchList);
}
// iteramos una vez mas sobre el resultado sobrante en el diccionario de referecias
// `matchList`, y actualizamos el elemento de la cola con la que se hicieron match
for (let _indexmatchList = 0; _indexmatchList < matchList.length; _indexmatchList++) {
const index = matchList[_indexmatchList].index;
(this._queue[index] as any) = updateValue
}
}
else {
// si el argumento no es un arreglo, pero es un objeto... busca en la cola elementos que sean
// iguales el argumento para luego actualizar su valor
if (typeof _arg1 === 'object') {
// iteramos sobre la cola tomando los elementos de cada ciclo en una varaible de referencia `item`
for (let _queueIndex = 0; _queueIndex < this._queue.length; _queueIndex++) {
const item = this._queue[_queueIndex];
// iteramos sobre cada propiedad de la referencia, para luego iterar sobre las propiedades del argumento
// y asi poder pasarlos por parametro a la funcion `compareObjets`
for (let [key_base, val_base] of Object.entries(_arg1)) {
for (let [key_compare, val_compare] of Object.entries(item)) {
if (key_base === key_compare) {
if (typeof val_base == 'object' && typeof val_compare === 'object') {
// si la funcion hace `match` actualizamos la posicion del elemento en la cola
if (compareObjets(val_base, val_compare)) {
(this._queue[_queueIndex] as any) = updateValue
}
}
}
}
}
}
}
else throw new Error("Tipos de datos invalidos, esta funcion solo recibe Arreglos u objetos como parametros");
}
} catch (error) { console.error(error); }
}
/**
* Funcion para buscar las propiedades que coincidan con el escalón del objeto
* segun los indices del array
* @param {Array<string>} _arrKeys Niveles de los escalones
* @returns {T} Retorna un arrglo con los elementos semejantes a las keys dadas
* @example <caption>Buscar los elementos a la cola con un arreglo</caption>
* const source = new Queue()
* ...
* source.find(['attributes','name'])
*/
public find(_arrKeys: string[]): T[];
/**
* Funcion para actualizar
* todas las propiedades que coincidan con el objeto
* @param {{[key:string]:any}} _objectReference Objeto de referencia
* @returns {T} Retorna un arrglo con los elementos semejantes a las keys dadas
* @example <caption> Buscar los elementos a la cola con una referencia </caption>
* const source = new Queue()
* ...
* const reference: T = {id: 12,attributes: {...} }
* source.updateByFind(reference)
*/
public find(_objectReference: { [key: string]: any }): T[];
/**
*
*/
public find(_arg1: string[] | { [key: string]: any }): unknown {
try {
/**
* Función recursiva para filtrar y devolver elementos
* cuyas propiedades hagan match con la llave (Key) asignada como argumento
* @param {string} key Llave con la que hacer match
* @param {any[]} arr Arreglo de objetos a filtrar
* @returns {any[]} Retorna un arreglo de referencias filtradas para hacer match con la _key_
*/
const findToArray = (key: string, arr: any[]): any[] => {
let returned: any[] = [];
for (let index = 0; index < arr.length; index++) {
const element = arr[index];
if (element.hasOwnProperty.call(element.value, key)) {
returned.push({
index: element.index,
value: element.value[key]
})
}
}
return returned;
}
/**
* Funcion recursiva para comparar objetos de manera profunda en sus propiedades
* @param {{[key:string]:any}} objet_base Objeto con la cual tener una referencia
* @param {{[key:string]:any}} objet_compare Objeto con la cual comparar segun la referencia
* @returns {boolean} si encuentra una coincidencia en las propiedades retorna `true`, en caso contrario `false`
*/
const compareObjets = (objet_base: { [key: string]: any }, objet_compare: { [key: string]: any }): boolean => {
for (let [key, val] of Object.entries(objet_base)) {
// si esta propiedad existe
if (objet_compare.hasOwnProperty(key)) {
// si el valor de la llave en el objeto comparador es diferente
if (objet_compare[key] !== val) {
// si el valor de la llave es de tipo objeto,
// aplicar recursividad a la funcion, asi hacemos un sondeo profundo a las propiedades
if (typeof objet_compare[key] == 'object') {
return compareObjets(objet_compare[key], val)
}
// console.error(`Propiedad ${key}: El valor ${objet_compare[key]} no es equivalente a ${val}`);
return false;
}
}
// si esta propiedad no existe
else {
// console.error(key, `propiedad no existe en el objeto comparador`);
return false;
}
}
return true
}
// si el argumento es un arreglo, busca todos los elementos de la cola que tengan como propiedades
// las mismas keys asignadas en el argumento __arg1_ y actualiza su valor a los establecidos en el argumento _updateValue_
if (Array.isArray(_arg1)) {
// creamos un diccionario de referencias
let matchList: { [key: string]: any }[] = []
// volcamos el diccionario las referencias
for (let _indexQueue = 0; _indexQueue < this._queue.length; _indexQueue++) {
const value = this._queue[_indexQueue];
const index = _indexQueue;
matchList.push({ index, value })
}
// iteramos sobre el argumento pasandole como parametro
// a la funcion `findToArray` el valor de la posicion del arreglo(Key)
// y segun lo que retorne dicha funcion se actualiza el diccionario de referencias
for (let _indexArg1 = 0; _indexArg1 < _arg1.length; _indexArg1++) {
const key = _arg1[_indexArg1];
matchList = findToArray(key, matchList);
}
// iteramos una vez mas sobre el resultado sobrante en el diccionario de referecias
// `matchList`, y actualizamos el elemento de la cola con la que se hicieron match
for (let _indexmatchList = 0; _indexmatchList < matchList.length; _indexmatchList++) {
const index = matchList[_indexmatchList].index;
matchList[_indexmatchList].value = this._queue[index];
}
return matchList
}
else {
// si el argumento no es un arreglo, pero es un objeto... busca en la cola elementos que sean
// iguales el argumento para luego actualizar su valor
if (typeof _arg1 === 'object') {
// incializamos un arreglo para convertirlo en un diccionario de referencias
let matchList: any[] = []
// iteramos sobre la cola tomando los elementos de cada ciclo en una varaible de referencia `item`
for (let _queueIndex = 0; _queueIndex < this._queue.length; _queueIndex++) {
const item = this._queue[_queueIndex];
// iteramos sobre cada propiedad de la referencia, para luego iterar sobre las propiedades del argumento
// y asi poder pasarlos por parametro a la funcion `compareObjets`
for (let [key_base, val_base] of Object.entries(_arg1)) {
for (let [key_compare, val_compare] of Object.entries(item)) {
if (key_base === key_compare) {
// si la funcion hace `match` empujamos el elemento en la cola a el diccionario de referencias
if (typeof val_base == 'object' && typeof val_compare === 'object') {
if (compareObjets(val_base, val_compare)) {
matchList.push({
index: _queueIndex,
value: item
})
}
}
}
}
}
}
return matchList
} else {
throw new Error("Tipos de datos invalidos, esta funcion solo recibe Arreglos u objetos como parametros");
}
}
} catch (error) { console.error(error); }
}
}
/**
* Interface de configuracion al momento de instanciar una cola
*/
interface config { length: undefined | number }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment