Modificar o crear subarrays

Alterar arrays existentes o crear fragmentos de array

Hay situaciones en las que tenemos un y queremos crear nuevos subarrays, es decir, un pequeño fragmento del original, o simplemente modificar el array original para hacer ciertos cambios, pero de una forma más general y no tener que hacerlo elemento a elemento.

Para ello, existen varios métodos relacionados, entre los que se encuentran los siguientes:

Método Descripción
.slice(start, end) Devuelve los elementos desde la posición start hasta end (excluído).
.splice(start, size) Altera el array, eliminando size elementos desde posición start. Muta
.splice(start, size, e1, e2...) Idem. Además inserta e1, e2... en la posición start. Muta
.copyWithin(pos, start, end) Altera el array, modificando en pos y copiando los ítems desde start a end. Muta
.fill(element, start, end) Altera los elementos del desde start hasta end. Muta

Vamos a ir explicándolos uno por uno.

Crear fragmento (slice)

El método .slice() devuelve los elementos del array desde la posición start hasta la posición end, permitiendo crear un nuevo array más pequeño con ese grupo de elementos. Recuerda que las posiciones empiezan a contar desde 0. En el caso de que no se proporcione el parámetro end, se devuelven todos los elementos desde la posición start hasta el final del array.

const letters = ["a", "b", "c", "d", "e"];

letters.slice(3); // ["d", "e"]
letters.slice(0, 2); // ["a", "b"]
letters.slice(4, 5); // ["e"]
letters.slice(2, 5); // ["c", "d", "e"]
letters.slice(-2); // ["d", "e"]

Observa que en el primer caso, al indicar un sólo parámetro, end es la posición del último elemento del array. En el último caso, al indicar un parámetro negativo, se empieza a contar desde el final. Recuerda que en todo momento, el original letters no sufre modificaciones.

Alterar fragmento (splice)

Por otro lado, el método .splice() realiza algo parecido a .slice() pero con una gran diferencia: modifica el array original. Además, en el método .splice() el segundo parámetro size no es la posición final del subarray (como en el caso anterior), sino el tamaño del array final, es decir, el número de elementos que se van a obtener desde la posición start.

const letters = ["a", "b", "c", "d", "e"];

letters.splice(0, 2); // Devuelve ["a", "b"]
letters // ["c", "d", "e"]

const letters = ["a", "b", "c", "d", "e"];

letters.splice(2, 1); // Devuelve ["c"]
letters // ["a", "b", "d", "e"]

Es decir, con el método .splice() devolvemos un con los elementos eliminados desde la posición start hasta la posición start + size. Por otro lado, el array original muta y se eliminan dichos elementos.

Es posible también indicar una serie de parámetros opcionales después de los mencionados, que permitirán además de la extracción de elementos, insertar dichos elementos justo donde hicimos la extracción.

Diferencias entre slice y splice

Veamos un ejemplo ilustrativo para entender bien la diferencia entre ambos:

const letters = ["a", "b", "c", "d", "e"];

// .slice() no modifica el array
letters.slice(2, 4); // Devuelve ['c', 'd']. El array no se modifica.

// .splice() si modifica el array
letters.splice(2, 2); // Devuelve ['c', 'd']. Ahora array = ['a', 'b', 'e']
letters.splice(1, 0, "z", "x"); // Devuelve []. Ahora array = ['a', 'z', 'x', 'b', 'e']

Observa que en el último caso de .splice(), además de extraer elementos, se insertan nuevos elementos. A raíz de este último ejemplo, mencionar que también podemos insertar elementos en una posición concreta del array de dos formas alternativas:

  • Utilizando .slice() y .concat() (no se muta el array original)
  • Utilizando .splice() y desestructuración (se muta el array original)

Veamos un ejemplo de cada forma, primero, utilizando .slice() y .concat():

const numbers = [1, 2, 3, 8, 9, 10];
const middlePart = [4, 5, 6, 7];

const firstPart = numbers.slice(0, 3); // [1, 2, 3]
const lastPart = numbers.slice(3, 6); // [8, 9, 10]

firstPart.concat(middlePart, lastPart); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

numbers // [1, 2, 3, 8, 9, 10] (numbers no ha mutado)

Ahora, otro ejemplo, utilizando .splice() y desestructuración. Ten en cuenta que el resultado en esta ocasión lo tendremos en la constante numbers:

const numbers = [1, 2, 3, 8, 9, 10];
const middlePart = [4, 5, 6, 7];

numbers.splice(3, 0, ...middlePart); // [] (Elementos eliminados, en este caso, ninguno)

numbers // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (numbers ha mutado)

Como se puede ver, se ha hecho la misma operación de dos formas diferentes.

Repetir fragmento (copyWithin)

Es posible tener un array al que queremos hacer ciertas modificaciones donde .slice() y .splice() se quedan cortos (o no resultan cómodos). Veamos algunos métodos introducidos en ECMAScript que nos permiten crear una versión modificada de un array:

El primero de ellos, copyWithin(pos, start, end) nos permite alterar el array, de modo que, empezando en la posición pos, copiará los elementos que están desde la posición start hasta la posición end. El parámetro end es opcional, de modo que si no se indica, se asume que end es el tamaño del array.

Veamos algunos ejemplos que alteran sucesivamente el array letters:

const letters = ["a", "b", "c", "d", "e", "f"];

// Estos métodos modifican el array original
letters.copyWithin(3, 0, 3); // ["a", "b", "c", "a", "b", "c"]
letters.copyWithin(3, 1); // ["a", "b", "c", "b", "c", "a"]
letters.copyWithin(4, 0, 1); // ["a", "b", "c", "b", "a", "a"]

Ten en cuenta que en el ejemplo anterior, la constante letters se va alterando en cada ejecución del método .copyWithin(), ya que no sólo devuelve el array, sino que muta el original. Utiliza structuredClone() si necesitas crear un nuevo array sin mutar el original.

Reducir el tamaño de un array

También, en ciertos casos, nos podría interesar reducir el tamaño de un array para quedarnos con sus primeros elementos y descartar el resto. Hay una forma muy sencilla y rápida que es modificar directamente el tamaño del array mediante la propiedad .length. Por ejemplo, hacer un numbers.length = 4 en un array de 8 elementos, reducirá el array a los primeros 4 elementos.

// Mediante slice()
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
const newNumbers = numbers.slice(0, 4);

newNumbers // [1, 2, 3, 4], numbers no cambia

// Mediante .length
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
numbers.length = 4;

numbers // [1, 2, 3, 4], numbers cambia

No crea un nuevo array, sino que reduce el tamaño del actual y descarta el resto de elementos.

Rellenar un array (fill)

Existe un método que nos permite rellenar el con los elementos indicados. Se le puede indicar unos parámetros opcionales start y end para establecer la posición de inicio y/o fin donde queremos rellenar, y así sólo alterar un fragmento del array.

Ten en cuenta que con .fill() estamos alterando el .

Veamos algunos ejemplos:

const letters = ["a", "b", "c", "d", "e", "f"];

// Estos métodos modifican el array original
letters.fill("Z", 0, 5); // ["Z", "Z", "Z", "Z", "Z", "f"]
letters.fill("AA", 0, 2); // ["AA", "AA", "AA", "Z", "Z", "f"]
letters.fill(1); // [1, 1, 1, 1, 1]
new Array(5).fill(5); // [5, 5, 5, 5, 5]

Observa que en el último caso, con new Array(5) creamos un array de 5 elementos undefined y lo rellenamos con números 5 con el método .fill().

También podríamos utilizar un enfoque más funcional y hacer algo similar con el método .map(), uno de los métodos que tienen los . La diferencia es que en este caso, no se muta el original, y por otro lado, devolvemos el nuevo construido:

const elements = [1, 2, undefined, undefined, 5];

elements.fill(10); // [10, 10, 10, 10, 10]
elements.map(element => 10); // Equivalente al anterior, sin mutar el original

const elements = [1, 2, undefined, undefined, 5];

elements.fill(10, 2, 4); // [1, 2, 10, 10, 5]
elements.map(element => !element ? 10 : element); // Equivalente al anterior, sin mutar el original

Si te interesa este enfoque, hablamos sobre ello más adelante, en el tema Array functions.

Tabla de contenidos