HOWTO · Java
Cambiar un array en Java
Este artículo muestra cómo cambiar un array en Java
En esta página
Desplazar un array puede referirse a dos operaciones distintas. Una rotación mueve los elementos en círculo y los conserva todos; una rotación a la derecha de dos posiciones mueve los dos últimos elementos al principio. En cambio, eliminar los elementos iniciales devuelve una secuencia más corta y descarta esos valores. Elija la rotación si necesita conservar el contenido del array, y omitir elementos si solo quiere procesar el sufijo.
Salvo que se indique lo contrario, los ejemplos realizan una rotación a la derecha. Una distancia positiva rota a la derecha y una negativa, a la izquierda. Las distancias mayores que la longitud del array pueden reducirse mediante el módulo de esa longitud. Los arrays tienen longitud fija, así que un método que devuelve un array nuevo deja intacto el original de quien lo llama solo si no lo reasigna ni lo modifica.
Los ejemplos son programas completos de Java; se muestra la salida del ejemplo del algoritmo de malabarismo. Las etiquetas incluidas en los bloques de salida permanecen en inglés para conservar intactos los ejemplos.
Decida si necesita rotar o eliminar los elementos iniciales
Use un bucle o un array temporal si necesita un array de tipo primitivo, como int[]. Use Collections.rotate() si los datos ya están en una List o si puede tratar un array de tipos de referencia como una lista. Elija el algoritmo de malabarismo si necesita modificar el array sin asignar otro y puede aceptar un código más complejo. Use skip() si quiere descartar los primeros n elementos de un flujo; esto no es una rotación y no conserva la longitud original.
Rote un array en el propio lugar con un bucle
Este método realiza un desplazamiento a la derecha cada vez. Guarda el último valor antes de mover los demás elementos una posición a la derecha y luego coloca el valor guardado en el índice cero. El ejemplo comienza con cinco enteros y rota dos posiciones a la derecha. Modifica el array recibido, usa espacio adicional constante y tarda O(n × k), donde n es la longitud del array y k la distancia normalizada.
Ejecute este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] values = {1, 2, 3, 4, 5};
int distance = 2;
if (values.length > 0) {
int steps = Math.floorMod(distance, values.length);
for (int step = 0; step < steps; step++) {
int last = values[values.length - 1];
for (int i = values.length - 1; i > 0; i--) {
values[i] = values[i - 1];
}
values[0] = last;
}
}
System.out.println(Arrays.toString(values));
}
}
Math.floorMod normaliza las distancias positivas y negativas a un valor entre cero y uno menos que la longitud del array. La comprobación de longitud evita dividir por cero y deja sin cambios un array vacío. Una distancia normalizada de cero también deja el array intacto. Este método de desplazamientos repetidos es sencillo para distancias pequeñas; con arrays o distancias grandes, los dos métodos siguientes mueven cada elemento una sola vez.
Rote mediante un array temporal
Asigne un segundo array si quiere una correspondencia directa entre índices y puede disponer de O(n) espacio adicional. Para rotar a la derecha, normalice primero la distancia a steps para admitir distancias negativas o mayores que la longitud. El elemento que estaba en el índice i pasa a ((long) i + steps) % n; el valor intermedio long evita el desbordamiento al sumar índices int válidos. Si el array está vacío, salga del método antes de aplicar el módulo.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] values = {1, 2, 3, 4, 5};
int distance = 2;
int[] rotated = new int[values.length];
if (values.length > 0) {
int steps = Math.floorMod(distance, values.length);
for (int i = 0; i < values.length; i++) {
int destination = (int) (((long) i + steps) % values.length);
rotated[destination] = values[i];
}
}
System.out.println(Arrays.toString(rotated));
}
}
La fórmula de destino hace que los índices que superan la última posición vuelvan al principio. La suma long se mantiene dentro del rango para cualquier longitud válida de array Java; después, el módulo genera un destino entre cero y values.length - 1. Sumar el mismo valor normalizado de steps módulo la longitud del array es una correspondencia uno a uno: cada índice de origen llega a un destino distinto y se conserva el orden relativo. El array de origen permanece intacto; si quiere que el resultado ocupe su lugar, use el array devuelto en vez del original.
Rote una lista con Collections.rotate()
Collections.rotate() opera sobre una List: una distancia positiva rota a la derecha y una negativa, a la izquierda. Para un array de tipos de referencia, Arrays.asList(array) crea una lista de tamaño fijo respaldada por ese mismo array. Puede sustituir elementos y rotar la lista, pero no añadir ni eliminar elementos. Al convertir la lista de nuevo en un array, se obtiene otro array independiente. Los arrays de tipos primitivos, como int[], no se convierten en List<Integer> mediante Arrays.asList; convierta los valores a sus clases envoltorio o use un algoritmo específico para arrays.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
Integer[] values = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(values);
Collections.rotate(list, 2);
Integer[] rotated = list.toArray(new Integer[0]);
System.out.println(Arrays.toString(rotated));
}
}
En este caso, la lista y values comparten el almacenamiento de los elementos, así que al rotar la lista también cambia el orden de los elementos del array. El array rotated, creado por separado, también contiene los valores rotados. Este método es conciso para listas y arrays de objetos, pero convertir datos primitivos en objetos requiere envolverlos en sus clases correspondientes.
Rote el array en el propio lugar con el algoritmo de malabarismo
El algoritmo de malabarismo divide el array en ciclos. Para una rotación a la izquierda de d posiciones, cada índice actual lee el valor del índice current + d, que vuelve al principio al alcanzar la longitud del array. En el código, calcule el índice resultante sin desbordamiento con esta expresión: current >= n - d ? current - (n - d) : current + d. Como d está normalizado entre cero y n - 1, el resultado queda entre cero y n - 1; si d es cero, devuelve current sin cambios. El número de ciclos independientes es gcd(n, d): cada ciclo desplaza valores por su recorrido hasta volver al índice inicial. El método realiza O(n) movimientos y usa O(1) espacio adicional, lo que puede ser útil si se quiere evitar asignar otro array.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] values = {1, 2, 3, 4, 5};
int rightDistance = 2;
int n = values.length;
if (n > 0) {
int rightSteps = Math.floorMod(rightDistance, n);
int leftDistance = (n - rightSteps) % n;
int cycles = gcd(n, leftDistance);
for (int start = 0; start < cycles; start++) {
int saved = values[start];
int current = start;
while (true) {
int next = current >= n - leftDistance
? current - (n - leftDistance)
: current + leftDistance;
if (next == start) break;
values[current] = values[next];
current = next;
}
values[current] = saved;
}
}
System.out.println(Arrays.toString(values));
}
private static int gcd(int a, int b) {
while (b != 0) {
int remainder = a % b;
a = b;
b = remainder;
}
return a;
}
}
[4, 5, 1, 2, 3]
El código primero normaliza la distancia solicitada hacia la derecha y la guarda en rightSteps. Luego obtiene la distancia equivalente hacia la izquierda con (n - rightSteps) % n. Para un array de cinco elementos, las distancias a la derecha 2 y -2 se normalizan a dos y tres pasos, respectivamente, lo que equivale a rotar tres y dos posiciones a la izquierda. Integer.MIN_VALUE también se maneja de forma segura porque se normaliza antes de restarlo. Una rotación a la izquierda lee el siguiente índice de cada ciclo y vuelve al principio al llegar al final del array. El cálculo condicional del código evita sumar current y leftDistance cuando el resultado superaría n - 1; cualquiera de las dos ramas devuelve un índice entre cero y n - 1, incluso si la suma directa excedería Integer.MAX_VALUE. gcd(n, leftDistance) indica cuántos ciclos hay. Si la distancia normalizada es cero, gcd(n, 0) es n y el cálculo condicional devuelve current, por lo que cada valor se escribe de nuevo en la misma posición. La comprobación de longitud gestiona el array vacío antes de calcular el módulo. Los métodos del bucle y del array temporal son más fáciles de mantener; elija el algoritmo de malabarismo cuando realmente necesite su espacio adicional constante.
Omita los elementos iniciales con la API de Stream
Use skip() si quiere excluir los valores iniciales del resultado en vez de trasladarlos al final. Devuelve un flujo con los elementos restantes; al convertirlo en un array, se obtiene uno más corto y la fuente no cambia. Si la cantidad que se omite es igual o mayor que el número de elementos, el resultado queda vacío. skip() requiere una cantidad no negativa; valide o limite el valor recibido si podría ser negativo.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] values = {1, 2, 3, 4, 5};
long count = 2;
int[] remainder = Arrays.stream(values).skip(count).toArray();
System.out.println(Arrays.toString(remainder));
}
}
Arrays.stream(values) crea un flujo de enteros, skip(count) omite sus primeros count elementos y toArray() recopila los restantes en un array primitivo nuevo. Es una opción práctica para obtener un sufijo, pero asigna espacio para el resultado y no sirve como sustituto de una rotación cuando es necesario conservar todos los elementos.