En este capítulo se resuelven algunos problemas que involucran vectores. Para ese fin se emplean las estructuras for y for-of, así como los métodos iterativos disponibles para matrices estudiados en el capítulo anterior. En general, los problemas que involucran arreglos, se resuelven de forma más sencilla (aunque no necesariamente más eficiente) empleando los métodos disponibles para el trabajo con arrays.
Por ejemplo, para calcular el valor de la siguiente expresión:
\[ \sum_{i=1}^{n}{v_i} \]
Es decir, calcular la sumatoria de los elementos de un vector "v", como el siguiente:
var v = [1, 2, 4, 5, 6, 8, 12, 23, 25, 42, 2, 6, 7, 3, 112];
La forma más simple consiste en llamar al método sum:
v.sum()
Igualmente (sobre todo si no se trabaja en la calculadora), se puede recurrir al método reduce:
v.reduce((s,e)=>s+e)
Es posible, también, emplear el método forEach:
var s = 0; v.forEach(e => s+=e); s
En este caso, como forEach simplemente ejecuta su función para cada uno de los elementos del array (v), el acumulador "s" debe ser iniciado antes del método y mostrado al final del mismo.
Se puede emplear también la estructura for-of, que es una variante de la estructura for y que tiene la siguiente sintaxis:
for (eofarray) instrucciones;
Donde las instrucciones son ejecutadas para cada uno de los elementos e del array. Estando el elemento e disponible en las instrucciones del ciclo.
Empleando esta estructura, la solución es similar a la del método forEach:
var s = 0; for (let e of v) s+=e; s
Como for-of no recibe una función, sino directamente las instrucciones, se escribe directamente la instrucción que suma los elementos "e" del vector.
Por supuesto, también se puede emplear la recursividad para resolver este tipo de problemas. Así, con una función flecha inmediatamente invocada (la cual cuenta con una función recursiva anidada: "sum"), el problema se resuelve con:
(v=>{sum=i=>i>=0?sum=sum(i-1)+v[i]:0;return sum(v.length-1)})(v) s
Como ya se vio previamente, una sumatoria (o productoria) con límites definidos, puede ser traducida directamente en un ciclo for, siendo los límites del ciclo los límites de la sumatoria (o productoria) y la variable de la sumatoria (o productoria) el contador del ciclo. El acumulador (la variable que almacena el resultado) debe iniciar en 0 si es una sumatoria y en 1 si es una productoria.
Así, para calcular la sumatoria, con la estructura for, se escribe:
var s = 0; for (let i=0; i<v.length; i++) s+=v[i]; s
Es importante recordar que, cuando se trabaja con vectores (y objetos en general), las variables son punteros, es decir variables que sólo guardan la dirección de memoria del lugar donde están almacenados los datos, pero no los datos en sí. Por esa razón, para efectivamente copiar un vector, se debe emplear el método slice (o si se trabaja en la calculadora, se puede emplear también el método copy).
Ejemplos
Promedio de un vector de números
En este ejemplo se programa un método para calcular el promedio de los valores almacenados en un vector "x", programando la expresión:
Al ser un problema sencillo, puede ser codificado directamente (sin necesidad de elaborar un algoritmo): el contador del ciclo "i", debe comenzar en 0 e ir hasta "n-1", incrementando en 1 en cada repetición del ciclo. El acumulador que se emplee, por ejemplo "s", debe comenzar en cero y en cada repetición del ciclo se le debe añadir el valor de x[i].
Sólo para que la lógica resulte aún más clara, se elabora el diagrama de flujo respectivo:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"promedio","key":-1,"loc":"172 -460"},{"category":"Input","text":"vector de números: x","key":-3,"loc":"171.99999999999994 -410.4666427612303"},{"category":"Conditional","text":"n==0 ","key":-5,"loc":"171.99999999999994 -301.6332496643064"},{"category":"Output","text":"lanzar error:\n \"vector vacío\"","key":-4,"loc":"319.0000000000004 -142.99999999999994"},{"category":"Process","text":"s = 0","key":-2,"loc":"38.85404968261713 -254.33321380615212"},{"category":"Process","text":"i = i+1","key":-7,"loc":"-44.00000000000014 -145.44982967376689"},{"category":"Start","text":"fin","key":-9,"loc":"171.99999999999986 41.65581652323428"},{"category":"Output","text":"s/n","key":-10,"loc":"38.85404968261713 -11.22199312845845"},{"category":"Process","text":"n = num. de elementos en x","key":-11,"loc":"171.99999999999994 -358.9332855224607"},{"category":"For","text":"i<n","key":-6,"loc":"38.85404968261713 -145.44982967376689"},{"category":"Process","text":"i = 0","key":-12,"loc":"38.85404968261713 -199.7998565673826"},{"category":"Process","text":"s = s+x[i]","key":-13,"loc":"38.85404968261713 -76.09980278015117"}],"linkDataArray":[{"from":-5,"to":-4,"fromPort":"R","toPort":"T","visible":true,"points":[208.15933227539057,-301.6332496643064,218.15933227539057,-301.6332496643064,319.0000000000004,-301.6332496643064,319.0000000000004,-243.42775586446112,319.0000000000004,-185.22226206461585,319.0000000000004,-175.22226206461585],"text":"Si"},{"from":-5,"to":-2,"fromPort":"L","toPort":"T","visible":true,"points":[135.84066772460932,-301.6332496643064,125.84066772460932,-301.6332496643064,38.85404968261713,-301.6332496643064,38.85404968261713,-291.61657104492167,38.85404968261713,-281.5998924255369,38.85404968261713,-271.5998924255369],"text":"No"},{"from":-4,"to":-9,"fromPort":"B","toPort":"R","points":[319.0000000000004,-119.79997131347653,319.0000000000004,-109.79997131347653,319.0000000000004,-108,319.0000000000004,-108,319.0000000000004,41.655816523234265,205.55952284071176,41.655816523234265,195.55952284071176,41.655816523234265]},{"from":-10,"to":-9,"fromPort":"B","toPort":"L","points":[38.85404968261713,1.4580212148032716,38.85404968261713,11.45802121480327,38.85404968261713,12,38.85404968261713,12,38.85404968261713,41.655816523234265,138.44047715928815,41.655816523234265,148.44047715928815,41.655816523234265]},{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[171.99999999999994,-444.73332138061505,171.99999999999994,-434.73332138061505,171.99999999999994,-434.73332138061505,171.99999999999994,-434.73332138061505,171.99999999999994,-434.73332138061505,171.99999999999994,-424.73332138061505]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[171.99999999999994,-396.1999641418455,171.99999999999994,-386.1999641418455,171.99999999999994,-386.1999641418455,171.99999999999994,-386.1999641418455,171.99999999999994,-386.1999641418455,171.99999999999994,-376.1999641418455]},{"from":-11,"to":-5,"fromPort":"B","toPort":"T","points":[171.99999999999994,-341.66660690307594,171.99999999999994,-331.66660690307594,171.99999999999994,-331.66660690307594,171.99999999999994,-331.66660690307594,171.99999999999994,-331.66660690307594,171.99999999999994,-321.66660690307594]},{"from":-2,"to":-12,"fromPort":"B","toPort":"T","points":[38.85404968261713,-237.06653518676737,38.85404968261713,-227.06653518676737,38.85404968261713,-227.06653518676737,38.85404968261713,-227.06653518676737,38.85404968261713,-227.06653518676737,38.85404968261713,-217.06653518676737]},{"from":-12,"to":-6,"fromPort":"B","toPort":"T","points":[38.85404968261713,-182.53317794799784,38.85404968261713,-172.53317794799784,38.85404968261713,-172.53317794799784,38.85404968261713,-172.53317794799784,38.85404968261713,-172.53317794799784,38.85404968261713,-162.53317794799784]},{"from":-6,"to":-13,"fromPort":"B","toPort":"T","visible":true,"points":[38.85404968261713,-128.36648139953593,38.85404968261713,-118.36648139953593,38.85404968261713,-110.86648139953593,38.85404968261713,-110.86648139953593,38.85404968261713,-103.36648139953593,38.85404968261713,-93.36648139953593],"text":"Si"},{"from":-13,"to":-7,"fromPort":"L","toPort":"B","points":[2.690673828124943,-76.09980278015117,-7.309326171875057,-76.09980278015117,-44.00000000000014,-76.09980278015117,-44.00000000000014,-97.14147691726666,-44.00000000000014,-118.18315105438214,-44.00000000000014,-128.18315105438214]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[-16.1634902954103,-145.44982967376689,-6.163490295410298,-145.44982967376689,-1.506393432617287,-145.44982967376689,-1.506393432617287,-145.44982967376689,3.1507034301757244,-145.44982967376689,13.150703430175724,-145.44982967376689]},{"from":-6,"to":-10,"fromPort":"R","toPort":"T","visible":true,"points":[64.55739593505854,-145.44982967376689,74.55739593505854,-144.72491483688344,106,-144.72491483688344,106,-47,38.85404968261713,-47,38.85404968261713,-38.833124160766396,38.85404968261713,-28.833124160766396],"text":"No"}]} })
La condición del ciclo es "i<n", porque las iteraciones deben repetirse mientras el contador "i" es menor a "n", no menor o igual a "n", porque el primer índice en javascript es 0, no 1.
El código respectivo, implementado como un método getter de la clase SV, es:
var SV = class {
#x;
constructor(...elementos) {
this.#x = elementos;
}
get x() {
return this.#x;
}
get promedio() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
let s = 0;
for (let i=0; i<n; i++) s+=x[i];
return s/n;
}
}
Observe que en el constructor se ha empleado un parámetro de tipo rest (resto), el cual se identifica escribiendo 3 puntos delante del nombre del parámetro (...elementos). Los parámetros de tipo rest deben ser o el único parámetro de la función o el último de los parámetros de la función. Un parámetro rest crea un array con todos los datos que recibe, por eso es empleado en el constructor, para que todos los datos que se pasen al mismo sean convertidos en un array.
Llamando al método con algunos valores de prueba, se obtiene:
new SV(1, 9, 12, 3, 5, 7, 12).promedio
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promedio
En el segundo ejemplo primero se genera (con rand) y muestra (con print) un vector con 20 números enteros aleatorios comprendidos entre 1 y 30. Luego, para que el getter promedio de la clase SV calcule el promedio de esos elementos, se emplea el operador spread (esparcir) que tiene el mismo símbolo que el operador rest (es decir 3 puntos consecutivos ...), sin embargo, hace lo contrario que rest, es decir, convierte un array en una secuencia de valores separados con comas (que es lo que se requiere en la clase SV).
Observe también que, antes de generar el vector con números aleatorios, se ha iniciado la semilla (randseed) en 1, para que siempre se genere la misma secuencia de números pseudoaleatorios, de manera que el ejemplo pueda ser replicado siempre (recuerde que, para volver a generar números realmente aleatorios, se debe asignar null a randseed ).
Otros ejemplos similares, pero generando los vectores con los métodos range y linspace, son:
var c = [].range(17, 51, 2); print(c);
new SV(...c).promedio
var d = [].linspace(5, 10, 21); print(d);
new SV(...d).promedio
El problema resuelto con la estructura for-of, es:
Object.defineProperty(SV.prototype, "promedioa", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
let s = 0;
for (let e of x) s+=e;
return s/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promedioa
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promedioa
El problema resuelto con el método forEach, es:
Object.defineProperty(SV.prototype, "promediob", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
let s = 0;
x.forEach(e=>s+=e);
return s/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promediob
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promediob
Como se vio en el anterior capítulo, además del valor del elemento ("e"), la función de forEach (en este caso la función flecha: e=>s+=e) puede recibir el índice y el array, sin embargo, en este ejemplo, no se reciben esos datos, porque no son empleados dentro de la función.
El problema resuelto con el método reduce, es:
Object.defineProperty(SV.prototype, "promedioc", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
return x.reduce((s,e)=>s+e)/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promedioc
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promedioc
En este caso, reduce devuelve la sumatoria, la cual se divide entre el número de elementos para obtener el promedio.
Al igual que la función de forEach y como ocurre con la mayoría de las funciones de los métodos de la clase Array, reduce, puede recibir, además del acumulador, el valor actual del elemento, el índice y el array en sí, pero, en este caso no son recibidos, porque no se requieren en la función.
Cono ya se vio en el anterior capítulo y aunque no es necesario en este caso, se puede asignar también un valor inicial al acumulador "s" de reduce (que, como se tratar de una sumatoria debe ser igual a 0):
Object.defineProperty(SV.prototype, "promediod", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
return x.reduce((s,e)=>s+e, 0)/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promediod
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promediod
El problema resuelto con el método sum, es:
Object.defineProperty(SV.prototype, "promedioe", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
return x.sum()/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promedioe
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promedioe
Igualmente, el problema puede ser resuelto con el método map:
Object.defineProperty(SV.prototype, "promediof", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
s = 0;
x.map(e=>s+=e);
return s/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promediof
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promediof
Desde el punto de vista de la eficiencia, esta no es la mejor opción, porque map devuelve un nuevo array con el mismo número de elementos que el array original (con los valores intermedios de la sumatoria), sin embargo, en este ejemplo, ese array no es empleado y por esa razón esta solución es menos eficiente (se pierde el tiempo en generar un array que, finalmente, no es empleado).
También se puede emplear el método every:
Object.defineProperty(SV.prototype, "promediog", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
s = 0;
x.every(e=>(s+=e,true));
return s/n;
},
configurable: true
});;
new SV(1, 9, 12, 3, 5, 7, 12).promediog
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promediog
Como el método every termina de iterar cuando un resultado es falso y en este caso es necesario que se itere para todos los elementos del array, la función debe devolver, siempre, un valor verdadero (true, 1 o cualquier valor equivalente a verdadero), porque de no ser así, un resultado equivalente a falso (como 0, cuando el primer elemento del array es 0) haría que las iteraciones terminen y el método devuelva el resultado erróneo 0.
Note que, en este ejemplo, para no emplear el comando return, las dos instrucciones de la función flecha (s+=e y true) han sido encerradas entre paréntesis y separadas con una coma (en la forma estándar se escribiría: e=>{s+=e; return true;}). Cuando dos o más instrucciones se escriben entre paréntesis y se separan con comas, son tratadas como si fueran de una sola instrucción Javascript. Las instrucciones dentro de los paréntesis son evaluadas una tras otra, pero, externamente, sólo se toma en cuenta el resultado devuelto por la última instrucción. Así, en este ejemplo, como la última instrucción es el valor booleano true ese es el valor final de las instrucciones escritas entre los paréntesis.
Igualmente, se puede emplear el método some (que es el complemento de every):
Object.defineProperty(SV.prototype, "promedioi", {
get() {
const x = this.x;
const n = x.length;
if (n===0) throw new Error("vector vacío");
s = 0;
x.some(e=>(s+=e,false));
return s/n;
},
configurable: true
});
new SV(1, 9, 12, 3, 5, 7, 12).promedioi
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
new SV(...b).promedioi
En este caso, como some termina cuando el resultado es verdadero y se quiere iterar para todos los elementos del array, el resultado de la función debe ser siempre falso (false, 0 o cualquier valor equivalente a falso).
De forma similar se pueden emplear los métodos find, findIndex, findLast, findLastIndex y filter. Sin embargo, es necesario dejar en claro que ninguno de estos métodos es el más adecuado para resolver este tipo de problemas, porque su propósito es otro: Verificar si todos los elementos cumplen una determinada condición (every), si alguno de los elementos cumple una determinada condición (some), verificar si un valor dado es uno de los elementos del array (find y findLast), encontrar la posición de un determinado elemento en el array (findIndex y findLastIndex) y obtener un array con los elementos que cumplen una determinada condición (filter).
En la asignatura se emplean estos métodos, para resolver este tipo de problemas, únicamente para comprender mejor la forma en que operan (su lógica), pero no deben ser empleados, en este tipo de problemas, en una aplicación real.
Vector de números aleatorios
En este ejemplo se elabora un método que genera un vector con "n" números aleatorios comprendidos entre 1 y 1000.
El problema puede ser resuelto fácilmente con el método rand: simplemente se generan "n" números aleatorios comprendidos entre 1 y 1000 y se redondea el vector resultante, tal como se muestra en la siguiente función:
function rand1000(n) {
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
return [].rand(n, 1, 1000).round();
};
Llamando al método con algunos valores de prueba, se obtiene:
randseed = 10;
rand1000(5)
rand1000(10)
rand1000(20)
rand1000(25)
rand1000(-10)
rand1000(5.7)
Si embargo, si no se tiene acceso al método rand, porque no se está trabajando en la calculadora o no se ha importado la librería array.js, el problema puede ser resuelto empleando la estructura for y la función estándar random.
Para transformar el número aleatorio comprendido entre 0 y 1, que es el resultado devuelto por random, en un número comprendido entre "li" y "ls", se aplica la siguiente expresión:
\[
\begin{aligned}
\text{Nú}&\text{mero aleatorio comprendido entre li y ls}=\\
&(\text{Número aleatorio comprendido entre 0 y 1})\times (\text{ls}-\text{li})+\text{li}
\end{aligned}
\]
Entonces, en cada repetición del ciclo for, que va desde 0 hasta "n-1", se genera y guarda un número aleatorio, como se muestra en el siguiente diagrama de flujo:
gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"rand1000","key":-1,"loc":"172 -460"},{"category":"Input","text":"número de elementos a generar: n","key":-3,"loc":"171.99999999999994 -410.4666427612303"},{"category":"Process","text":"v = []","key":-2,"loc":"171.99999999999997 -359.3332138061521"},{"category":"Process","text":"i = i+1","key":-7,"loc":"57.99999999999987 -250.44982967376689"},{"category":"Start","text":"fin","key":-9,"loc":"172.00000000000009 -63.34418347676573"},{"category":"Output","text":"v","key":-10,"loc":"171.99999999999997 -116.22199312845845"},{"category":"For","text":"i<n","key":-6,"loc":"171.99999999999997 -250.44982967376686"},{"category":"Process","text":"i = 0","key":-12,"loc":"171.99999999999997 -304.79985656738245"},{"category":"Process","text":"v[i] = random()*999+1","key":-13,"loc":"171.99999999999997 -181.09980278015115"}],"linkDataArray":[{"from":-10,"to":-9,"fromPort":"B","toPort":"T","points":[171.99999999999997,-103.5419787851967,171.99999999999997,-93.5419787851967,171.99999999999997,-91.07642044067359,171.99999999999997,-91.07642044067359,171.99999999999997,-88.61086209615047,171.99999999999997,-78.61086209615047]},{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[172.00000000000006,-444.73332138061534,172.00000000000006,-434.73332138061534,172.00000000000006,-434.73332138061517,171.99999999999997,-434.73332138061517,171.99999999999997,-434.73332138061505,171.99999999999997,-424.73332138061505]},{"from":-2,"to":-12,"fromPort":"B","toPort":"T","points":[171.99999999999997,-342.06653518676734,171.99999999999997,-332.06653518676734,171.99999999999997,-332.06653518676734,171.99999999999997,-332.0665351867674,171.99999999999997,-332.0665351867674,171.99999999999997,-322.0665351867674]},{"from":-12,"to":-6,"fromPort":"B","toPort":"T","points":[171.99999999999997,-287.53317794799784,171.99999999999997,-277.53317794799784,171.99999999999997,-277.53317794799784,171.99999999999997,-277.53317794799784,171.99999999999997,-277.53317794799784,171.99999999999997,-267.53317794799784]},{"from":-6,"to":-13,"fromPort":"B","toPort":"T","visible":true,"points":[171.99999999999997,-233.36648139953593,171.99999999999997,-223.36648139953593,171.99999999999997,-215.86648139953593,171.99999999999997,-215.86648139953593,171.99999999999997,-208.36648139953593,171.99999999999997,-198.36648139953593],"text":"Si"},{"from":-13,"to":-7,"fromPort":"L","toPort":"B","points":[93.007453918457,-181.09980278015115,83.007453918457,-181.09980278015115,57.99999999999986,-181.09980278015115,57.99999999999986,-202.14147691726663,57.99999999999986,-223.18315105438214,57.99999999999986,-233.18315105438214]},{"from":-7,"to":-6,"fromPort":"R","toPort":"L","points":[85.8365097045897,-250.44982967376689,95.8365097045897,-250.44982967376689,116.06658172607413,-250.44982967376689,116.06658172607413,-250.44982967376689,136.29665374755857,-250.44982967376689,146.29665374755857,-250.44982967376689]},{"from":-6,"to":-10,"fromPort":"R","toPort":"T","visible":true,"points":[197.70334625244138,-250.44982967376689,207.70334625244138,-249.72491483688344,270,-249.72491483688344,270,-152,171.99999999999997,-152,171.99999999999997,-143.83312416076637,171.99999999999997,-133.83312416076637],"text":"No"},{"from":-3,"to":-2,"fromPort":"B","toPort":"T","points":[171.99999999999997,-396.1999641418455,171.99999999999997,-386.1999641418455,171.99999999999997,-386.1999641418455,171.99999999999997,-386.5998924255369,171.99999999999997,-386.5998924255369,171.99999999999997,-376.5998924255369]}]} })
El código respectivo, implementado como un método getter de la clase "RAND", empleando la estructura for, redondeando los resultados a números enteros y luego probando el método con algunos valores, es:
var RAND = class {
#n;
constructor(número) {
this.#n = número;
}
get n() {
return this.#n;
}
get rand1000() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
const v= [];
for (let i=0; i<n; i++) v[i] = (Math.random()*999+1).round();
return v;
}
};
randseed = 10;
new RAND(5).rand1000
new RAND(10).rand1000
new RAND(20).rand1000
new RAND(25).rand1000
La solución, implementada empleando el método push (en lugar de una asignación directa), es:
Object.defineProperty(RAND.prototype, "rand1000_", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
const v = [];
for (let i=0; i<n; i++) v.push((Math.random()*999+1).round());
return v;
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000_
El problema puede ser resuelto, igualmente, con el método estático Array.from:
Object.defineProperty(RAND.prototype, "rand1000__", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
return Array.from({length:n}, ()=>(Math.random()*999+1).round());
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000__
El problema, resuelto con la estructura for-of, es:
Object.defineProperty(RAND.prototype, "rand1000a", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
const v = [];
for (const _ of [].zeros(n)) v.push((Math.random()*999+1).round());
return v;
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000a
Como el método for-of itera para cada uno de los elementos de un array y en este caso, ese array no existe, es necesario crear uno con ese número de elementos (en este ejemplo se crea con zeros). Luego se itera para cada uno de los elementos de ese array, pero no se emplea ninguno de esos elementos y por ello son recibidos en el parámetro "_" (que como se explicó, suele emplearse para identificar parámetros/variables, que son recibidos/declarados, pero que no son utilizados). Debido a que for-of, requiere la creación de un array adicional (cuyos elementos no se utilizan), no es la estructura más adecuada para resolver este problema, porque el crear ese array consume tiempo y memoria adicional.
Los "n" elementos del array pueden ser generados con cualquiera de los métodos disponibles: const, range, rand, Array.from, new Array, etc., sin que ello afecte ni la lógica ni el resultado obtenido (porque únicamente es importante que el array tenga el número correcto de elementos).
El problema puede ser resuelto también con el método forEach:
Object.defineProperty(RAND.prototype, "rand1000b", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [].zeros(n);
v.forEach((_,i,v)=>v[i]=(Math.random()*999+1).round());
return v;
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000b
Al igual que en la solución anterior se genera un array con "n" elementos (que tampoco son utilizados). Luego, con forEach, se itera para cada uno de esos elementos, pero ahora se recibe el índice "i", de cada elemento, para reemplazar ese elemento (v[i]) con el número aleatorio generado. Esta solución es un poco más eficiente que la anterior, porque solo se genera un array, pero, al igual que en el ejemplo anterior, los elementos del array generado no son empleados.
El problema resuelto con el método reduce (y zeros para generar el array), es:
Object.defineProperty(RAND.prototype, "rand1000c", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
return [].zeros(n).reduce(v=>(v.push((Math.random()*999+1).round()),v),[]);
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000c
Como no se emplean los elementos del array, en la función solo se recibe el primer parámetro (el acumulador "v") que se convertirá en el array con los números aleatorios. Por esa razón, el acumulador "v" inicia como un vector vacío ([]), luego, en cada iteración, se le añada un número aleatorio y se devuelve array con el nuevo elemento añadido. De esa manera, en la última iteración, reduce devuelve el array con todos los números aleatorios generados.
El problema puede ser resuelto, también, con el método some, aunque, como se explicó previamente, no es la opción correcta para este tipo de problemas:
Object.defineProperty(RAND.prototype, "rand1000d", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
const v = [];
[].zeros(n).some(()=>(v.push((Math.random()*999+1).round()),false));
return v;
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000d
Como ocurre con for=of, no se emplean los elementos del array generado (zeros), por lo que la función no recibe nada y para garantizar que el método itere para todos los elementos, la función devuelve siempre un valor false.
De la misma forma, se puede emplear el método every:
Object.defineProperty(RAND.prototype, "rand1000e", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
const v = [];
[].range(n).every(()=>(v.push((Math.random()*999+1).round()),true));
return v;
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000e
Que es prácticamente la misma solución que con some, sólo que ahora la función devuelve siempre true y el array se genera con range.
El problema puede ser resuelto, igualmente, con el método map.
Object.defineProperty(RAND.prototype, "rand1000f", {
get() {
const n = this.n;
if (n%1!==0 || n<0) throw new Error("El número debe ser entero positivo");
return Array.from({length:n}).map(()=>(Math.random()*999+1).round());
},
configurable: true
});
randseed = 10;
new RAND(5).rand1000f
Esta solución es similar a la lograda con reduce, en el sentido de que si bien no se emplean los elementos del array generado (el array de ceros), sí se emplea el array para reemplazar esos ceros con los valores aleatorios generados en la función.
Como en casi todos los casos, el problema puede ser resuelto también con find, findIndex, findLast, findLastIndex y filter, aunque, como también se dijo, no son los métodos más adecuados para resolver este tipo de problemas.