Arreglos 2

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.

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)

El método reduce asigna, en la primera iteración, el valor del primer elemento (1) al primer parámetro de la función (al acumulador "s") y el valor del segundo elemento (2) al segundo parámetro ("e"). En la función se suma a "s" el valor de "e" (1+2 = 3). En la siguiente iteración, el resultado de la anterior iteración (3) es asignado al acumulador "s" y el valor del siguiente elemento (4) a "e", con lo que se calcula un nuevo resultado (3+4 = 7). El método prosigue de esa manera, asignando el resultado de la iteración anterior a "s" y el valor del nuevo elemento a "e", hasta que se llega al último elemento, añadiendo el mismo a "s". Ahora, como no existen más elementos, el resultado de la función (la sumatoria) es devuelto por el método.

Es posible, también, emplear el método forEach:

var s = 0;
v.forEach(e => s+=e);
s

En este caso, debido a que la función que se manda a forEach sólo recibe, uno a uno, los elementos del vector (e), el acumulador "s" se inicializa en 0 fuera del método. En el método, en cada iteración, se suma a "s" el valor del elemento "e", con lo que, al terminar la última iteración, "s" tiene el valor de la sumatoria.

Se puede emplear también la estructura for-of, que es una variante de la estructura for y que tiene la siguiente sintaxis:

for (e of array) instrucciones;

Donde las instrucciones son ejecutadas para cada uno de los elementos e del array. El elemento e está disponible para que sea empleado 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

La única diferencia, con relación al método forEach es que, como la estructura for-of no recibe una función, sino que ejecuta instrucciones, en lugar de la función se escribe directamente la instrucción que suma a "s", uno a uno, los elementos "e" del vector. Es decir, en la primera iteración "e" vale 1 y se suma ese valor a "s", en la segunda "e" vale 2 y se suma ese valor a "s" y así sucesivamente.

Cuando no se dispone de un método adecuado para resolver el problema, se debe emplear la estructura for o la estructura for-of.

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 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:

\[ \bar{x} = \dfrac{\displaystyle\sum_{i=0}^{n-1}{x_i}}{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"}]} })

Observe que la condición del ciclo es "i<n", que es equivalente a la condición "i<=n-1", sólo que es más corta y más eficiente: se compara sólo si es menor, no si es menor o igual, además no es necesario restar 1 al número. Igualmente, dado que los índice (en este caso) son números enteros, la condición del ciclo podría ser "i!=n", porque el ciclo se debe repetir mientras el contador sea diferente al número de elementos del array. Cuando es igual el índice está apuntando a un elemento inexistente, debido a que (como se recordará) el primer índice de un array es 0 y el último n-1.

El código respectivo, es:

var promedio = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
let s = 0;
for (let i=0; i<n; i++) s += x[i];
return s/n;
};

Llamando a la función con algunos valores de prueba, se obtiene:

var a = [1, 9, 12, 3, 5, 7, 12];
promedio(a)
randseed = 1;
var b = [].rand(20, 1, 30).round(); print(b);
promedio(b)
var c = [].range(17, 51, 2); print(c);
promedio(c)
var d = [].linspace(5, 10, 21); print(d);
promedio(d)

Como se puede ver en estos ejemplos, antes de generar los vectores con números aleatorios, se ha iniciado la semilla (randseed) en 1, con lo que se genera la misma secuencia de números pseudoaleatorios (se recuerda que, para volver a generar números realmente aleatorios, se debe asignar el valor null a la variable randseed ).

El problema resuelto con la estructura for-of, es:

var promedioa = function(x) {
const n=x.length;
if (n===0) throw "vector vacío";
let s = 0;
for (let e of x) s+=e;
return s/n;
};
promedioa([].range(17, 51, 2))

En este caso, la estructura for-of, extrae uno a uno los elementos "e" del vector, los cuales se añaden al acumulador "s".

El problema resuelto con el método forEach, es:

var promediob = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
let s = 0;
x.forEach(e=>s+=e);
return s/n;
};
promediob([].range(17, 51, 2))

En cada iteración, el método forEach manda a la función (en este ejemplo una función flecha) el valor del elemento actual, ese valor es recibido (en este ejemplo) en la variable "e". Dentro de la función, ese valor es añadido a la variable "s" ("s+=e"), por lo tanto, en cada iteración, se añade a "s", el valor de un nuevo elemento, con lo que, al final del proceso "s" tiene el valor de la suma de todos los elementos del array. Como se vio en el capítulo anterior, además del valor del elemento ("e"), forEach manda también el índice (la posición) del elemento actual, así como el array en sí, sin embargo, en este ejemplo, no se reciben esos valores, porque no son utilizados dentro de la función.

El problema resuelto con el método reduce, es:

var promedioc = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
return x.reduce((s,e)=>s+e)/n;
};
promedioc([].range(17, 51, 2))

Como se explicó previamente, reduce devuelve el valor de la sumatoria, el cual es dividido entre el número de elementos, con lo que se obtiene el promedio.

Como sucede con casi todos los métodos iterativos para arrays, reduce manda, además, el índice actual y el array en sí, pero, al igual que con forEach estos valores no son recibidos, porque no se emplean dentro de la función.

Si en reduce se emplea un valor inicial (el parámetro opcional), ese valor es asignado al acumulador en la primera iteración (en lugar del primer elemento del array). Así, la solución del ejemplo, pero empleando un valor inicial, es:

Array.prototype.promedioc = function() {
const x = this;
const n = x.length;
if (n===0) throw "vector vacío";
return x.reduce((s,e)=>s+e, 0)/n;
};
[].range(17, 51, 2).promedioc()

En este caso, como se manda un valor inicial (0), reduce asigna ese valor al primer parámetro de la función (al acumulador) y asigna al segundo parámetro el valor del primer elemento. El resultado es el mismo porque, al ser el valor inicial 0, no afecta al resultado (pues es una sumatoria). La única diferencia es que ahora reduce hace una iteración más. En otros casos, sin embargo, el proporcionar (o no) un valor inicial, puede dar lugar a resultados completamente diferentes.

El problema resuelto con el método sum, es:

var promediod = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
return x.sum()/n;
};
promediod([].range(17, 51, 2))

Igualmente, el problema puede ser resuelto con el método map:

var promedioe = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
s = 0;
x.map(e=>s+=e);
return s/n;
};
promedioe([].range(17, 51, 2))

El método map opera de forma similar a forEach, excepto que (como ya se vio en el anterior capítulo) genera un nuevo array (de igual dimensión que el array original), donde cada elemento es el resultado devuelto por la función en cada iteración. En este ejemplo, ese array es simplemente ignorado, por lo que, para este problema en particular, el método map no es muy eficiente.

También se puede emplear el método every:

var promediof = function() {
const n = x.length;
if (n===0) throw "vector vacío";
s = 0;
x.every(e=>(s+=e,true));
return s/n;
};
promedio([].range(17, 51, 2))

Donde, para que el método itere para todos los elementos del array, la función devuelve true. Obviamente, debido a este paso adicional, no es un método adecuado para resolver este problema, sin embargo, es posible su uso, porque, a pesar de que su propósito es el verificar si todos los elementos de un array cumplen (o no) una determinada condición (el método termina y devuelve false, si la condición es falsa para cualquiera de los elementos), en cada iteración la función recibe el valor del elemento, el cual puede ser empleado igual que forEach, recordando que el valor devuelto por la función debe ser true (o un valor equivalente a true, como el número 1 por ejemplo).

Observe que en este caso la función tiene dos instrucciones "s+=e" y "true", por eso ha sido encerrada entre paréntesis y las instrucciones separadas con una coma (no con un punto y coma). Cuando el cuerpo de una función se encierra entre paréntesis, es tratada como una expresión, las instrucciones (separadas con comas) son evaluadas de forma secuencial y el valor de la última expresión (en este caso true) es el valor devuelto por la función. Se emplean paréntesis, simplemente porque la función resultante es más compacta, sin embargo, la función puede ser programada también de la forma tradicional, es decir con llaves y el comando return, como se muestra a continuación:

Array.prototype.promediof = function() {
const x = this;
const n = x.length;
if (n===0) throw "vector vacío";
s = 0;
x.every(e=>{s+=e; return true});
return s/n;
};
[].range(17, 51, 2).promediof()

Igualmente, se puede emplear el método some (que es el complemento de every):

var promediog = function(x) {
const n = x.length;
if (n===0) throw "vector vacío";
s = 0;
x.some(e=>(s+=e,false));
return s/n;
};
promediog([].range(17, 51, 2))

Al igual que con every, se fuerza a que some itere para todos los elementos del array, haciendo que la función devuelva false (porque some termina y devuelve true cuando la función es verdadera para cualquiera de los elementos del array).

De forma similar se pueden emplear los métodos find, findIndex, findLast, findLastIndex y filter. Sin embargo, se recalca que ninguno de estos métodos es adecuado para resolver este tipo de problemas, sólo son empleados en la asignatura (en este tipo de problemas) a manera de ejercicio, pero no deben ser empleados, en aplicaciones reales para resolver problemas similares al presente.

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 "El número debe ser entero positivo"; return [].rand(n, 1, 1000).round(); };

Llamando a la función con algunos valores de prueba, se obtiene:

randseed = 10;
rand1000(5)
rand1000(10)
rand1000(20)
rand1000(25)
rand1000(-10)
rand1000(5.7)

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]}]} })

Siendo el código respectivo:

var rand1000 = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo"; const v= [];
for (let i=0; i<n; i++) v[i] = Math.round(Math.random()*999+1);
return v;
};
randseed = 10;
rand1000(5)
rand1000(10)
rand1000(20)
rand1000(25)

La solución, implementada empleando el método push (en lugar de una asignación directa), es:

var rand1000 = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [];
for (let i=0; i<n; i++) v.push(Math.round(Math.random()*999+1));
return v;
};
randseed = 10;
rand1000(5)
rand1000(10)
rand1000(20)
rand1000(25)

El problema puede ser resuelto, también, empleando la estructura for-of:

var rand1000a = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [];
for (const _ of [].zeros(n)) v.push(Math.round(Math.random()*999+1));
return v;
};
randseed = 10;
rand1000a(5)

Como el método for-of itera para cada uno de los elementos de un array, pero en este caso no existe ese array, primero se crea uno, con Array.from({length:n}) (un array con "n" elementos "undefined"), entonces for-of itera para cada uno de los elementos de ese array. No obstante, como esos elementos no son empleados en el ciclo, se denota ese hecho recibiéndolos en el parámetro "_". En cada repetición del ciclo for-of, se genera y añade al vector "v", un número aleatorio.

Dado que en este tipo de solución, no se emplean los elementos del array, sólo interesa el número de elementos, los "n" elementos pueden ser generados con cualquiera de los métodos conocidos: const, range y zeros, etc.

Por ejemplo, con el método forEach y range (para generar el array), la solución es:

var rand1000b = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [];
[].range(n).forEach(()=>v.push(Math.round(Math.random()*999+1)));
return v;
};
randseed = 10;
rand1000b(5)

Donde, con range, se crea un vector con "n" elementos (de 1 al n) y se llama al método desde ese vector. Al igual que el caso anterior, como no se emplean los elementos del array, la función no recibe ningún elemento.

El problema resuelto con el método reduce y zeros (para generar el array), es:

var rand1000c = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
return [].zeros(n).reduce(v=>(v.push(Math.round(Math.random()*999+1)),v),[]);
};
randseed = 10;
rand1000c(5)

En este ejemplo, al igual que en los anteriores, no se emplean los elementos del array, por lo que la función solo recibe el primer parámetro (el acumulador) "v". Se manda como valor inicial un vector vacío ([]), el cual es asignado en la primera iteración a "v", luego, en cada iteración, se genera un número aleatorio que se añade (con push) a "v" y se devuelve el vector con el nuevo valor añadido (, v). Por lo tanto, a partir de la segunda iteración, reduce asigna el vector con el nuevo elemento al acumulador "v", de manera que "v" siempre tiene el vector con el último elemento añadido. Finalmente en la última iteración reduce devuelve el valor de "v" (el vector con todos los números aleatorios añadidos).

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:

var rand1000d = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [];
[].zeros(n).some(()=>(v.push(Math.round(Math.random()*999+1)),false));
return v;
};
randseed = 10;
rand1000d(5)

Igual que en los casos anteriores, no se emplean los elementos del array, razón por la cual la función no recibe ningún valor y, para que el método itere con todos los elementos del array, la función devuelve false.

De la misma forma, se puede emplear el método every:

var rand1000e = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
const v = [];
[].zeros(n).every(()=>(v.push(Math.round(Math.random()*999+1)),true));
return v;
};
randseed = 10;
rand1000e(5)

Que esencialmente es igual a la solución anterior, solo que en este caso el array se genera con el método range y la función devuelve true para que el método itere con todos los elementos del array.

El problema puede ser resuelto, igualmente, con el método map.

var rand1000f = function(n) {
if (n%1!==0 || n<0) throw "El número debe ser entero positivo";
return [].zeros(n).map(()=>Math.round(Math.random()*999+1));
};s
randseed = 10;
rand1000f(5)

Al igual que en los casos anteriores, como no se emplean los elementos del array, la función no recibe ningún valor, pero como el método map devuelve un nuevo array con valores iguales a los resultados de la función y la función devuelve (en cada iteración) un número aleatorio, el array resultante es directamente el array de números aleatorios devuelto por map.

De forma similar y al igual que en el ejemplo anterior, el problema puede ser resuelto, también, con find, findIndex, findLast, findLastIndex y filter, sin embargo, se reitera que estos métodos no son la opción correcta para resolver este tipo de problemas. Se emplean en este capítulo solamente para adquirir práctica en su uso, pero no deben ser empleados, en estos casos, en la solución de problemas reales.