jardinBit/src/notas/arreglos.md

323 lines
8.0 KiB
Markdown

---
title: "Arreglos: Fundamentos"
---
Los arreglos (*arrays*) son una manera sistematizada de almacenar múltiples variables del mismo tipo.
En combinación con ciclos `while` o `for`, nos permiten programar rutinas que actúan sobre diversos valores a la vez.
[[Ciclos while y for]](/notas/ciclos.html)
# Planteamiento del problema
## Una variable
Partimos de este ejemplo de código de animación básica con acumuladores, en el que un punto se mueve hacia la derecha y al llegar al borde vuelve a empezar su camino en la izquierda.
[[Animación básica con acumuladores]](/notas/animacion-basica.html)
```java
// 1) variable para almacenar la posición horizontal del punto
float px;
void setup(){
size(400, 400);
strokeWeight(10);
stroke(255);
px = 0; // 2) valor inicial de posición
}
void draw(){
background(0);
// 3) dibuja el punto con pos. horizontal: px
// y posición vertical: 200
point(px, 200);
// 4) incrementa la posición horizontal
px = px + 2;
// 5) y si llega al borde derecho, reinicia
if(px > width){
px = 0;
}
}
```
## Múltiples variables, sin arreglos
Supongamos que queremos tener más puntos moviéndose de la misma manera, pero empezando en diferentes posiciones.
Previo a utilizar arreglos, lo que haríamos sería crear una variable por cada punto y repetir por cada una los 5 pasos del ejemplo previo.
Un ejemplo con tres puntos se vería así:
```java
// 1) variables para almacenar las posiciones horizontales de los puntos
float px1, px2, px3;
void setup(){
size(400, 400);
strokeWeight(10);
stroke(255);
// 2) valor inicial de posición
px1 = 0;
px2 = 50;
px3 = 200;
}
void draw(){
background(0);
// 3) dibuja los puntos con pos. horizontal: px
// y posición vertical: 200
point(px1, 200);
point(px2, 200);
point(px3, 200);
// 4) incrementa las posiciones horizontales
px1 = px1 + 2;
px2 = px2 + 2;
px3 = px3 + 2;
// 5) y si alguna llega al borde derecho, reinicia
if(px1 > width){
px1 = 0;
}
if(px2 > width){
px2 = 0;
}
if(px3 > width){
px3 = 0;
}
}
```
Tal vez con tres puntos todavía es manejable, pero imagina cómo se vería el código con 5, 10, o 100 puntos.
Los arreglos nos permitirán tener un código con una extensión al primero, aunque tengamos miles de puntos.
## Con arreglos
El mismo programa, con arreglos, podría quedar de la siguiente forma:
```java
// 1) arreglo para almacenar las posiciones horizontales de los puntos
float[] px;
void setup(){
size(400, 400);
strokeWeight(10);
stroke(255);
// 2) crea e inicializa arreglo con 3 puntos:
px = new float[3];
px[0] = 0;
px[1] = 50;
px[2] = 200;
}
void draw(){
background(0);
// por cada elemento del arreglo...
for (int i=0; i<px.length; i++) {
// 3) dibuja los puntos con pos. horizontal: px[i]
// y posición vertical: 200
point(px[i], 200);
// 4) incrementa la posición horizontal
px[i] = px[i] + 2;
// 5) y si alguna llega al borde derecho, reinicia
if (px[i] > width) {
px[i] = 0;
}
}
}
```
# Notación
Los símbolos que nos van a indicar que estamos usando arreglos son los corchetes `[ ]`.
## Declaración
Declaramos un arreglo con su tipo de dato y los corchetes:
```java
float[] posiciones; // declara arreglo
```
## Creación
A diferencia de otras variables básicas, antes de poder usar un arreglo necesitamos crearlo.
Al crearlo, indicamos el número de elementos que contendrá:
```java
posiciones = new float[100]; // crea arreglo de 100 elementos
```
## Atributo `.length`
Los arreglos tienen un atributo `.length` que nos indica el número de elementos que contiene.
```java
println( posiciones.length ); // imprime tamaño del arreglo
```
## Asignación y lectura
Cada elemento del arreglo tiene un **índice** numérico con el cual lo podemos ubicar. Podemos visualizarlo también como una *dirección*.
Los elementos están numerados a partir de 0, y llegan hasta `.length - 1`.
Por ejemplo, un arreglo de 5 elementos tendrá los índices 0, 1, 2, 3, 4.
Accederemos a cada índice con los corchetes `[ ]`:
```java
posiciones[0] = 200; // asigna 200 a la primera posición del arreglo
posiciones[1] = 10; // asigna 10 a la segunda posición del arreglo
```
Esa notación la podemos utilizar en lugar de cualquier variable.
Por ejemplo, aquí la tercera posición del arreglo se comporta como acumulador, leyendo el valor del elemento, sumándole 5, y guardando el resultado en la misma posición:
```java
posiciones[2] = posiciones[2] + 5;
```
Cuando queremos utilizar un índice fuera del rango del arreglo, recibiremos un error `ArrayIndexOutOfBoundsException`.
## Declaración, creación y asignación
Alternativamente, podemos declarar y crear un arreglo directamente con una lista de elementos:
```java
float[] posiciones = { 200, 100, 50, 20 }; // declara y crea arreglo
```
El arreglo tendrá el tamaño correspondiente a la cantidad de elementos dados.
## Ciclos `for`
Una de las principales ventajas de los arreglos es que como podemos acceder a sus elementos a través de un valor numérico (el *índice*), podemos hacer que ese sea una variable que se incrementa de uno en uno (un *contador*).
La notación más utilizada es con una variable de tipo `int` llamada `i` que funciona como índice, y que recorre cada posición del arreglo con un ciclo `for` de la siguiente forma:
```java
for( int i=0; i<posiciones.length; i++){
// realiza acciones con posiciones[i]
}
```
Lo que escribiremos dentro del ciclo `for` requiere un trabajo previo de identificar qué acciones son las que tomamos por cada elemento del arreglo, qué tienen en común, para entonces abstraerlas en términos de `i`.
### Inicializaciones
Este ejemplo inicializa todos los valores del arreglo en 0:
```java
for( int i=0; i<posiciones.length; i++){
posiciones[i] = 0;
}
```
Y este asigna un valor aleatorio distinto a cada elemento:
```java
for( int i=0; i<posiciones.length; i++){
posiciones[i] = random(width);
}
```
Aquí le asignamos un valor dado por un acumulador:
```java
float x = 0;
for( int i=0; i<posiciones.length; i++){
posiciones[i] = x;
x = x + 10;
}
```
### Lectura
Este ejemplo dibuja tantos puntos como elementos del arreglo, usando el valor leído como posición horizontal:
```java
for( int i=0; i<posiciones.length; i++){
point( posiciones[i], 200 );
}
```
### Incrementos, condicionales
Este ciclo fue extraído del ejemplo de arriba. Aquí cada elemento del arreglo se incrementa y cuando supera un límite es reiniciado a 0
```java
for( int i=0; i<posiciones.length; i++){
posiciones[i] = posiciones[i] + 10;
if( posiciones[i] > width ){
posiciones[i] = 0;
}
}
```
# Multiplicidades
Podemos crear tantos arreglos como queramos. Si todos tienen el mismo tamaño, los podemos utilizar para referirse a diferentes características de una misma entidad.
Por ejemplo, los puntos del ejemplo de arriba pueden tener diferente posición vertical además de diferente posición horizontal. Este *sketch* inicializa 100 de ellos con posición aleatoria y los mueve en la misma dirección, reiniciándolos al llegar al final:
```java
// 1) arreglos para almacenar posiciones x,y de los puntos
float[] px;
float[] py;
void setup() {
size(400, 400);
strokeWeight(10);
stroke(255);
// 2) crea e inicializa arreglos con 100 elementos:
px = new float[100];
py = new float[100];
for (int i=0; i<px.length; i++) {
px[i] = random(width);
py[i] = random(height);
}
}
void draw() {
background(0);
// por cada elemento del arreglo...
for (int i=0; i<px.length; i++) {
// 3) dibuja los puntos con pos. horizontal: px[i]
// y posición vertical py[i]
point(px[i], py[i]);
// 4) incrementa la posición horizontal
px[i] = px[i] + 2;
// 5) y si alguna llega al borde derecho, reinicia
if (px[i] > width) {
px[i] = 0;
}
}// cierra ciclo for
}
```
¿Cómo harías que los puntos se muevan en el eje vertical en vez del horizontal?
¿Cómo harías que al llegar al borde derecho, los puntos cambien su posición vertical a una nueva posición aleatoria?
¿Cómo harías que cada punto tuviera una velocidad distinta?