Está en la página 1de 16

Arreglos

H. Tejeda

Marzo 2016

Índice

1. Declaración de arreglos 1

2. Inicialización de arreglos 4

3. Uso de subı́ndices variables en un arreglo 5

4. Declaración y uso de arreglos de objetos 8

5. Búsqueda y uso de arreglos paralelos 10

6. Paso y devolución de arreglos en métodos 14

Para guardar un valor y usarlo se han usado variables. Se han usado ciclos que permiten “reciclar”
variables para ser usadas varias veces; ya que después de haber creado una variable, asignarle un
valor, usar el valor, y luego, en iteraciones sucesivas en el ciclo, se reusa la variable con valores
diferentes.

En ocasiones se tienen situaciones en las cuales guardar un solo valor a la vez en memoria no es
suficiente. Por ejemplo, un supervisor de ventas que vigila 20 empleados podrı́a querer determinar
si cada empleado ha hecho ventas por encima o por debajo del promedio. Con el valor de las ventas
del primer empleado ingresado en una aplicación, no se puede determinar si está por encima o por
debajo porque todavı́a no se sabe el promedio hasta que se tengan los 20 valores. Desafortunada-
mente, sı́ se intente asignar 20 valores de venta a la misma variable, cuando se asigne el valor para
el segundo empleado, este reemplaza el valor del primer empleado.

Una solución posible es crear 20 variables de ventas de empleados separadas, cada una con un
nombre único, para poder guardar todas las ventas hasta que se pueda calcular el promedio. Una
desventaja es que se ocupan 20 nombres de variables diferentes para asignar los valores y 20 sen-
tencias de asignación diferentes. Para los nombres de las 20 variables diferentes. la sentencia que
calcula el total de la venta será compleja, como:

total = primeraCant + segundaCant + terceraCant + ...

1
La sentencia anterior trabajarı́a para 20 vendedores, pero ¿qué sucederı́a si se tienen 5,000 vende-
dores?

1. Declaración de arreglos

La mejor solución al problema de los 5,000 vendedores es creando un arreglo. Un arreglo es una
lista de datos con nombre teniendo todos ellos el mismo tipo. Cada dato es un elemento del
arreglo. Se declara una variable arreglo de la misma forma como se declara una variable simple,
pero se inserta un par de corchetes después del tipo. Por ejemplo, para declarar un arreglo de
valores double para guardar las ventas, se puede escribir lo siguiente:

double [] ventas;

Nota. Se puede declarar una variable arreglo en Java poniendo los corchetes después del nombre
del arreglo, como en double ventas[];. Este formato es empleado en C y C++, pero el formato
preferido entre los programadores de Java es poniendo los corchetes después del tipo de la variable
y antes del nombre de la variable.

Se puede dar cualquier identificador legal que se quiera para un arreglo, pero los programadores de
Java nombran los arreglos siguiendo las mismas reglas usadas para variables, el nombre inicia con
minúscula y letras mayúsculas iniciando palabras subsecuentes. Adicionalmente, varios programa-
dores observan una de las siguientes convenciones para hacer más énfasis que el nombre representa
un grupo de datos:

Los arreglos son nombrados frecuentemente usando un sujeto plural como ventas.

Los arreglos son nombrados frecuentemente agregando una palabra final que implique un
grupo, como listaVentas, tablaVentas, o arregloVentas.

Después de crear una variable arreglo, se necesita reservar espacio de memoria. Se usa el mismo
procedimiento para crear un arreglo que el empleado para crear un objeto.

Para declarar un arreglo y reservar memoria para este se hace en dos procesos distintos. Para
reservar localidades de memoria para 20 valores de ventas, se declara la variable arreglo y luego se
crea el arreglo mediante dos sentencias como sigue:

double [] ventas;
ventas = new double [20];

Al igual que con los objetos, se puede declarar y crear un arreglo en una sola sentencia con lo
siguiente:

double [] ventas = new double [20];

2
Con la sentencia anterior se reservan 20 localidades de memoria para 20 valores double. Se puede
distinguir cada dato ventas de los otros con un subı́ndice. Un subı́ndice es un entero contenido
dentro de corchetes que especifica uno de los elementos del arreglo. Cualquier arreglo de elementos
en Java está numerado iniciando con cero, ası́ que se pueden usar correctamente subı́ndices de 0
hasta 19 al trabajar con un arreglo de 20 elementos. Es decir, el primer elemento del arreglo ventas
es ventas[0] y el último elemento es ventas[19].

En otros lenguajes de programación el primer elemento del arreglo es el elemento uno, lo cual es un
error común al olvidar que en Java el primer elemento en un arreglo es el elemento cero. También
lo anterior hace que se olvide que el subı́ndice del último elemento es uno menos que el tamaño del
arreglo y no el tamaño de este. Para no olvidar el uso correcto se puede pensar que el subı́ndice
de un elemento indica la cantidad de elementos que le preceden. Si se emplea un subı́ndice que es
negativo, o igual a, o mayor que el tamaño del arreglo, el subı́ndice está fuera de lı́mites y un
mensaje de error es generado.

Cuando se trabaja con algún elemento del arreglo, se emplea de igual forma como se hace con una
variable. Por ejemplo, para asignar un valor al primer elemento de ventas en un arreglo, se usa
una sentencia de asignación simple, tal como la siguiente:

ventas[0] = 12345.0;

Para mostrar el último elemento del arreglo ventas de tamaño 20, se escribe:

System.out.println(ventas[19]);

Cuando se declara o accesa un arreglo, se puede usar cualquier expresión para indicar el tamaño,
siempre y cuando esta dé un entero. Para declarar un arreglo double llamado valoresMoneda, se
podrı́a usar cualquiera de las siguientes:

Una constante literal entera


double [] valoresMoneda = new double [10];
Una constante con nombre entera
double [] valoresMoneda = new double [CANT ELEMS];
Una variable entera
double [] valoresMoneda = new double [cantElems];
Un cálculo que involucre variables con enteros, o dé un entero
double [] valoresMoneda = new double [x + y * z];
Un valor entero devuelto por un método
double [] valoresMoneda = new double [getElementos()];

Actividad 1. Escribir una aplicación que declare y cree un arreglo para guardar al menos cinco
valores double. Que asigne a cada uno de los elementos del arreglo un valor arbitrario y que muestre
en pantalla las asignaciones hechas.

3
2. Inicialización de arreglos

Una variable que tiene un tipo primitivo, como un int, guarda un valor. Una variable con un tipo
referencia, como un arreglo, guarda una dirección de memoria donde un valor está guardado. Los
nombres de arreglos contienen referencias, al igual como todos los objetos Java.

No se asigna dirección de memoria cuando se declara un arreglo usando sólo un tipo de dato,
corchetes, y un nombre. El nombre de la variable arreglo tiene el valor especial null, que significa
que el identificador no está asociado con alguna dirección, como sucede con el valor de numeros
que es null en la siguiente declaración:

int [] numeros;

Al emplear la palabra reservada new para definir un arreglo, el nombre arreglo recibe el valor de
una dirección de memoria, como se hace en la siguiente sentencia al definir numeros

int [] numeros = new int [10];

En esta declaración numeros tiene una dirección, pero cada elemento de numeros tiene el valor de
cero porque es un arreglo de enteros. Los elementos en un arreglo float o double tienen asignado
0.0. Por defecto, los elementos de un arreglo char tienen asignado ‘0̆000’, el cual es el valor Unicode
para el carácter null, y los elementos de un arreglo boolean tienen asignado false. En arreglos
de objetos, incluyendo String, cada elemento tiene asignado null por defecto.

Además de asignar un valor a un elemento de un arreglo, como en:

numeros[0] = 45;

Se pueden también asignar valores diferentes al valor por defecto a los elementos de un arreglo en
la creación. Para inicializar un arreglo, se usa una lista de inicialización de valores separados por
comas y encerradas entre paréntesis. Dando valores para todos los elementos en un arreglo también
es llamado poblar un arreglo.

Por ejemplo, si se quiere crear un arreglo llamado multiplosDiez y guardar los primeros seis
múltiplos de diez en el arreglo, se puede declarar como sigue:

int[] multiplosDiez = {10, 20, 30, 40, 50, 60};

Observar el punto y coma al final de la sentencia.

Cuando se pobla un arreglo en la creación dando una lista inicialización, no se da el tamaño


del arreglo, el tamaño es asignado de acuerdo a la cantidad de valores que se pongan en la lista
de inicialización. Por ejemplo, el arreglo multiplosDiez definido previamente tiene tamaño seis.
También, cuando se inicializa un arreglo, no se requiere usar la palabra reservada new, la nueva
memoria es asignada de acuerdo al tamaño de la lista dada.

4
No se puede directamente inicializar una parte de un arreglo en Java. En caso de que se requiera se
deberá hacer individualmente, una vez que se haya creado el arreglo usando la palabra reservada
new.

Actividad 2. Modificar la actividad 1 para declarar, crear, e inicializar el arreglo usando una lista
de inicialización.

3. Uso de subı́ndices variables en un arreglo

Si se trata cada elemento de un arreglo como una entidad individual, no hay ventaja en declarar un
arreglo respecto a variables individuales de tipos primitivos. El poder de los arreglos se da cuando
se usan subı́ndices que son variables, en vez de subı́ndices que sean valores constantes.

Suponer que se declara un arreglo de cinco enteros que guarda cinco puntuaciones, como se muestra
enseguida:

int [] arregloPunt = 13, 23, 54, 79, 95;

Luego se quiere realizar la misma operación con cada elemento del arreglo, tal como incrementar
cada puntuación por una cantidad constante. Para incrementar cada elemento de arregloPunt por
cinco puntos, por ejemplo, se puede escribir lo siguiente:

final int INCREMENTO = 5;


arregloPunt[0] += INCREMENTO;
arregloPunt[1] += INCREMENTO;
arregloPunt[2] += INCREMENTO;
arregloPunt[3] += INCREMENTO;
arregloPunt[4] += INCREMENTO;

Con un arreglo pequeño, la tarea es manejable, requiriendo solo cinco sentencias. Sin embargo, se
puede reducir la cantidad de código necesario usando una variable como subı́ndice. Entonces, se
puede usar un ciclo para realizar la aritmética con cada elemento, como en el siguiente ejemplo:

final int INCREMENTO = 5;


for (int sub = 0; sub < 5; ++sub)
arregloPunt[sub] += INCREMENTO;

La variable sub es puesta a cero, y entonces es comparado a cinco. Como el valor de sub es
menor que cinco, el ciclo se ejecuta y tres es agregado a arregloPunt[0]. Luego, la variable
sub es incrementada y se hace uno, que sigue siendo menor que cinco, ası́ que el ciclo se ejecuta
nuevamente, arregloPunt[1] es incrementado por cinco, y ası́ sucesivamente. Un proceso que toma
cinco sentencias ahora toma solamente una. Considerar lo que sucederı́a si el arreglo hubiese tenido
100 elementos, habrı́a requerido 95 sentencias adicionales, pero el único cambio requerido, usando
el segundo método, es el cambio del tamaño del arreglo a 100 en la segunda parte del ciclo for.

5
Cuando una aplicación contiene un arreglo y se quiere usar cada elemento del arreglo en alguna
tarea, se sugiere usar ciclos que varı́en la variable de control del ciclo desde cero hasta uno menos
que el tamaño del arreglo. Estas tareas pueden ser el alterar cada valor en el arreglo, sumar todos
los valores en el arreglo, o mostrar cada elemento en el arreglo. En una aplicación que incluya
un arreglo es conveniente declarar una constante simbólica igual al tamaño del arreglo y usar la
constante simbólica como un valor limitante en cada ciclo que procese el arreglo. De esta forma,
si el tamaño del arreglo cambia más adelante, sólo se necesita modificar el valor guardado en la
constante simbólica, para no tener que buscar y modificar el valor limitante en cada ciclo que
procesa el arreglo. Un ejemplo serı́a como el siguiente:

int [] arregloPunt = {13, 23, 54, 79, 95};


final int INCREMENTO = 5;
final int CANT DE PUNT = 5;
for (int sub = 0; sub < CANT DE PUNT; ++sub)
arregloPunt[sub] += INCREMENTO;

Este formato tiene dos ventajas, primero, el uso de la constante simbólica, CANT DE PUNT, el lector
entiende que se está procesando cada elemento del arreglo por el tamaño del arreglo entero. Segundo,
si el tamaño del arreglo cambia porque se agregaron o quitaron puntuaciones, sólo se ocupa cambiar
el valor de la constante simbólica una sola vez.

Una segunda opción, es usar un campo, variable de instancia, al que es asignado automáticamente
un valor para cada arreglo que es creado; el campo length contiene la cantidad de elementos en el
arreglo. El siguiente ejemplo repite el código previo mostrando como se usa este campo como valor
limitante en la parte central del ciclo for.

int [] arregloPunt = {13, 23, 54, 79, 95};


final int INCREMENTO = 5;
for (int sub = 0; sub < arregloPunt.length; ++sub)
arregloPunt[sub] += INCREMENTO;

Un error frecuente del programador es intentar usar length como un método del arreglo, escribiendo
arregloPunt.length(), en vez de usarlo como un campo. Una variable de instancia o campo objeto
como length es también llamado una propiedad del objeto.

Java también soporta un ciclo for mejorado. Este ciclo permite recorrer un arreglo sin indicar
los puntos de inicio y terminación para la variable de control del ciclo. Para mostrar cada elemento
del arreglo llamado arregloPunt con el ciclo avanzado se hace ası́:

for (int val : arregloPunt)


System.out.println(val);

val es definido del mismo tipo que el arreglo nombrado que está después de los dos puntos. Dentro
del ciclo, val adquiere, uno a la vez, cada valor del arreglo. Se puede leer como, “Para cada val en
arregloPunt, mostrar val”. El ciclo for avanzado es conocido también como ciclo foreach.

6
Uso de una parte del arreglo

En ocasiones no se quiere usar cada valor en un arreglo. Por ejemplo, suponer que se escribe un
programa que permite a un estudiante meter hasta 10 puntuaciones y luego calcular y mostrar el
promedio. Para permitir 10 puntuaciones, se crea un arreglo que puede guardar 10 valores, pero
como el estudiante podrı́a meter menos de 10 valores, se podrı́a usar una parte del arreglo, como
se muestra en el código 1.
1 import j a v a . u t i l . ∗ ;
2 public c l a s s P r o m e d i o F l e x i b l e {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int [ ] p u n t u a c i o n e s = new int [ 1 0 ] ;
5 int p u n t u a c i o n = 0 ;
6 int c u e n t a = 0 ;
7 int t o t a l = 0 ;
8 f i n a l int SALIR = 9 9 9 ;
9 f i n a l int MAX = 1 0 ;
10 Scanner e n t r a d a = new Scanner ( System . i n ) ;
11 System . out . p r i n t ( ” Entrar p u n t u a c i ón : ” ) ;
12 puntuacion = entrada . nextInt ( ) ;
13 while ( c u e n t a < MAX && p u n t u a c i o n != SALIR ) {
14 i f ( p u n t u a c i o n != SALIR ) {
15 puntuaciones [ cuenta ] = puntuacion ;
16 t o t a l += p u n t u a c i o n e s [ c u e n t a ] ;
17 System . out . p r i n t ( ” I n g r e s a r s i g u i e n t e p u n t u a c i ón o ” +
18 SALIR + ” para s a l i r : ” ) ;
19 puntuacion = entrada . nextInt ( ) ;
20 }
21 c u e n t a++;
22 }
23 System . out . p r i n t l n ( ” Las p u n t u a c i o n e s dadas son : ” ) ;
24 f o r ( int x = 0 ; x < c u e n t a ; ++x )
25 System . out . p r i n t ( p u n t u a c i o n e s [ x ] + ” ” ) ;
26 System . out . p r i n t l n ( ”\n El promedio e s ” + ( t o t a l ∗ 1 . 0 / c u e n t a ) ) ;
27 }
28 }

Código 1: Aplicación PromedioFlexible.

La aplicación PromedioFlexible declara un arreglo que puede guardar diez puntuaciones. Al usua-
rio se pide la primera puntuación; luego, en ciclo while la puntuación es puesta en el arreglo
puntuaciones. Luego la puntuación es agregada a un total, y al usuario se le pide ingresar otra
puntuación o un valor SALIR de 999 para parar la petición de números. En el ciclo while se revisa
para que no más de diez puntuaciones sean ingresadas y que el usuario no dé 999 para salir. Des-
pués de cada puntuación entrada, la variable contar es incrementada, y sirve para dos propósitos:
para indicar el elemento donde la siguiente puntuación deberá ser guardada, y para cuando el ciclo
termina saber la cantidad de puntuaciones dadas. La variable count luego es usada para controlar
la salida del ciclo for y para el cálculo del promedio.

Actividad 3. Modificar la aplicación descrita en la 2 para que se use un ciclo for para mostrar
cada uno de los elementos del arreglo.

7
4. Declaración y uso de arreglos de objetos

Se pueden declarar arreglos que guarden elementos de cualquier tipo, incluyendo objetos. Por
ejemplo, suponer que se ha creado la clase Asalariado, código 2, la cual incluye dos campos de
datos, numero y salario, un constructor, y métodos accesores para cada campo.
1 public c l a s s A s a l a r i a d o {
2 private int numero ;
3 private double s a l a r i o ;
4 A s a l a r i a d o ( int n , double s ) {
5 numero = n ;
6 salario = s ;
7 }
8 public int getNumero ( ) {
9 return numero ;
10 }
11 public int g e t S a l a r i o ( ) {
12 return s a l a r i o ;
13 }
14 }

Código 2: La clase Asalariado.

Se pueden crear objetos individuales Asalariado con nombres únicos, como los siguientes:

Asalariado pintor, electricista, plomero;


Asalariado trabajador1, trabajador2, trabajador3;

En varios programas puede ser más conveniente crear un arreglo de objetos Asalariado. Un arreglo
llamado plantilla que guarde siete objetos Asalariado se define como:

Asalariado[] plantilla = new Asalariado[7];

La sentencia reserva suficiente memoria para siete objetos Asalariado llamados plantilla[0]
hasta plantilla[6]. La sentencia no construye los objetos Asalariado, por lo tanto se reque-
rirá llamar al constructor siete veces. Se quiere númerar a los trabajadores empezando en 500 y
con un salario de $1,200, y como el constructor de la clase Asalariado requiere dos argumentos,
número del asalariado y salario, el siguiente ciclo construye los siete objetos:

final int NUM INICIAL = 500;


final double SALARIO = 1200.0;
for (int x = 0; x < plantilla.length; ++x)
plantilla[x] = new Asalariado(NUM INICIAL + x, SALARIO);

Como x varı́a desde 0 hasta 6, cada uno de los siete objetos plantilla es construido con un
número de empleado que es 500 más que x, y con el mismo salario de $1,200.00, como se asigna
por la constante SALARIO.

8
Otras clases contienen solo el constructor por defecto, el cual es dado automáticamente cuando
no hay ningún constructor escrito en la clase. Para construir un arreglo de objetos usando un
constructor por defecto, también se debe llamar al constructor usando la palabra reservada new
para cada elemento declarado del arreglo. Por ejemplo, suponer que se ha creado una clase llamado
ArticuloInventario sin haber escrito un constructor. Para crear un arreglo de 1,000 objetos
ArticuloInventario, se podrı́a hacer ası́:

final int CANT ARTS = 1000;


ArticuloInventario[] articulos = new ArticuloInventario[CANT ARTS];
for (int x = 0; x < CANT ARTS; ++x)
articulos[x] = new ArticuloInventario();

Para usar un método que pertenece a un objeto que es parte de un arreglo, se inserta la notación
subı́ndice apropiada después del nombre arreglo y antes del punto que precede al nombre del método.
Por ejemplo, para mostrar los datos de los siete asalariados guardados en el arreglo plantilla, se
puede escribir lo siguiente:

for (int x = 0; x < plantilla.length; ++x)


System.out.println(plantilla[x].getNumero() + " " +
plantilla[x].getSalario());

La colocación del subı́ndice entre corchetes es después de plantilla para indicar que el método
“pertenece” a un elemento particular de la plantilla.

Uso de ciclos for avanzados con objetos

Se puede emplear el ciclo for avanzado para recorrer un arreglo de objetos. Para mostrar los datos
de los siete asalariados guardados en el arreglo plantilla, se puede hacer de esta forma:

for (Asalariado trabajador : plantilla)


System.out.println(trabajador.getNumero() + " " +
trabajador.getSalario());

En este ciclo, trabajador es una variable local que representa cada elemento de plantilla en
turno. Usando el ciclo for avanzado se evita usar un valor limitante para el ciclo y de usar un
subı́ndice siguiendo a cada elemento.

Manipulación de arreglos de String

Como con cualquier otro objeto, se puede crear un arreglo de objetos String. Por ejemplo, se puede
guardar los nombres de los departamentos de una empresa como sigue:

String[] departNombres = {"Contabilidad", "Recursos Humanos", "Ventas"};

9
Se acceden los nombres de los departamentos como otros arreglos objeto. Por ejemplo, se puede
usar el siguiente código para mostrar la lista de String guardadas en el arreglo departNombres:

for (int a = 0; a < departNombres.length; ++a)


System.out.println(departNombres[a]);

Actividad 4. Crear la clase EquipoBaloncesto, la cual contendrá un arreglo String para guardar
los nombres, de exactamente cinco jugadores, de un equipo de baloncesto. Cuando se declare el
arreglo en la clase, este deberá ser creado. Agregar un método que ponga el nombre de un miembro
del equipo. Este método requiere una posición y un nombre, y usa la posición como subı́ndice al
arreglo String para asignar el nombre. Agregar un método accesor que devuelve el nombre de un
miembro del equipo; este método requiere un valor usado como subı́ndice para determinar cual
nombre se devuelve del arreglo. Agregar también a la clase EquipoBaloncesto un campo String,
para guardar el nombre del equipo; agregar método accesor y mutador para este campo. Crear
una aplicación que muestre de manera completa el uso de la clase EquipoBaloncesto, es decir,
deberá declarar y crear un objeto del tipo EquipoBaloncesto, pedir al usuario los nombres del
equipo y mostrar los miembros del equipo.

5. Búsqueda y uso de arreglos paralelos

Suponer que una empresa manufactura diez artı́culos. Cuando un cliente pone una orden se necesita
determinar si la clave del artı́culo es válida. Cuando se desea determinar si una variable tiene uno
de varios valores válidos y estos son secuenciales, por ejemplo entre 201 y 220, la siguiente sentencia
if, que usa el operador lógico Y, puede hacer la revisión para poner la bandera a true si el artı́culo
es válido.

final int INF = 201;


final int SUP = 220;
boolean articuloValido = false;
if (articuloOrdenado >= INF && articuloOrdenado <= SUP)
articuloValido = true;

Cuando los valores válidos no son secuenciales, por ejemplo, 101, 108, 201, 213, 266, 304, etc., se
puede codificar la siguiente sentencia if anidada profundamente o una comparación larga O para
determinar la validez.

if (articuloOrdenado == 101)
articuloValido = true;
else if (articuloOrdenado == 108)
articuloValido = true;
else if (articuloOrdenado == 201)
articuloValido = true;
// y ası́ sucesivamente

10
Otra solución elegante y compacata es comparando la variable articuloOrdenado con una lista de
valores en un arreglo, un proceso llamado búsqueda en un arreglo. Se inicializa el arreglo con los
valores válidos y luego se emplea la sentencia for para recorrer el arreglo, poniendo una variable
booleana a true cuando un apareamiento es encontrado.

int [] valoresValidos = {101, 108, 201, 213, 266,


304, 311, 409, 411, 412};
for (int x = 0; x < valoresValidos.length; ++x)
if (articuloOrdenado == valoresValidos[x])
articuloValido = true;

El uso del ciclo for en esta solución permite revisar cualquier cantidad de valores válidos sin tener
que modificar ninguna parte, ya que valoresValidos.length tiene el tamaño actual del arreglo.

Uso de arreglos paralelos

Cuando se tienen dos arreglos con la misma cantidad de elementos y sus elementos se relacionan
entre ellos por la posición, entonces se puede usar simultáneamente el mismo subı́ndice en ambos
arreglos.

Un arreglo paralelo es uno con la misma cantidad de elementos como otro y para el cual los
valores en los elementos correspondientes están relacionados.

Suponiendo que para el código mostrado previamente se configura un arreglo que tenga los precios
de los artı́culos, entonces estos precios deberán aparecer en el mismo orden que sus correspondientes
números de artı́culo en el arreglo valoresValidos. El ciclo for que encuentra el número válido de
artı́culo también encuentra el precio, como se muestra en la aplicación EncontrarPrecio, código
3.
1 import j a v a x . swing . JOptionPane ;
2 public c l a s s E n c o n t r a r P r e c i o {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int [ ] v a l o r e s V a l i d o s = { 1 0 1 , 1 0 8 , 2 0 1 , 2 1 3 , 2 6 6 ,
5 304 , 311 , 409 , 411 , 412};
6 double [ ] p r e c i o s = { 2 2 . 5 , 1 3 . 6 0 , 1 8 . 7 0 , 5 4 . 2 0 , 2 3 . 3 0 ,
7 54.80 , 56.20 , 78.90 , 5.50 , 9.90};
8 String articuloStr ;
9 int a r t i c u l o O r d e n a d o ;
10 double p r e c i o A r t i c u l o = 0 . 0 ;
11 boolean a r t i c u l o V a l i d o = f a l s e ;
12 a r t i c u l o S t r = JOptionPane . sh ow In pu tD ia lo g ( null ,
13 ” I n g r e s a r e l número de a r tı́ c u l o que q u i e r e o r d e n a r ” ) ;
14 articuloOrdenado = Integer . parseInt ( a r t i c u l o S t r ) ;
15 f o r ( int i =0; i <v a l o r e s V a l i d o s . l e n g t h ; ++i )
16 i f ( a r t i c u l o O r d e n a d o == v a l o r e s V a l i d o s [ i ] ) {
17 a r t i c u l o V a l i d o = true ;
18 precioArticulo = precios [ i ] ;
19 }
20 if ( articuloValido )
21 JOptionPane . showMessageDialog ( null , ” El p r e c i o d e l a r tı́ c u l o ” +

11
22 articuloOrdenado + ” es $” + p r e c i o A r t i c u l o ) ;
23 else
24 JOptionPane . showMessageDialog ( null ,
25 ”¡Lo s i e n t o ! , a r tı́ c u l o i n g r e s a d o no vá l i d o ” ) ;
26 }
27 }
Código 3: La aplicación EncontrarPrecio que accede información en arreglos paralelos.

Nota. En lugar de arreglos paralelos conteniendo números de artı́culos y precios, se puede crear una
clase llamada Articulo conteniendo dos campos, articuloOrdenado y precioArticulo. Luego se
crea un arreglo simple de objetos que encapsulan los números y los precios.

En el código 3 se compara articuloOrdenado con cada uno de los diez valoresValidos. No


importa, que por ejemplo, articuloOrdenado sea igual al primer valor, se terminan haciendo
nueve comparaciones extras, y estas serán siempre falsas. Tan pronto como un apareamiento para
articuloOrdenado es encontrado, es más eficiente forzar la salida temprana del ciclo for. Una
forma fácil de lograrlo es poner x a un valor alto dentro del bloque de sentencias ejecutadas cuando
hay un apareamiento. Enseguida se muestra la forma como se puede hacer. También considerar
para una mayor eficiencia poner los artı́culos más comunes al inicio.

for (int x = 0; x < CANTIDAD DE ARTICULOS; ++x)


if (articuloOrdenado == valoresValidos[x]) {
articuloValido = true ;
precioArticulo = precios[x];
x = CANTIDAD DE ARTICULOS;
}

Algunos programadores consideran inapropiado modificar la variable de control de ciclo dentro del
cuerpo del ciclo for; porque consideran que sólo se debe hacer en la tercera sección del ciclo for.
Por lo que la salida forzada del ciclo la realizan con otra expresión booleana en la sección central
del ciclo for, de esta forma, como se muestra enseguida, x deberá estar entre el rango antes de
cada iteración y articuloValido no deberá estar puesta a true.

for (int x = 0; x < CANTIDAD DE ARTICULOS && !articuloValido; ++x)


if (articuloOrdenado == valoresValidos[x]) {
articuloValido = true ;
precioArticulo = precios[x];
}

Búsqueda en un arreglo por un rango de apareamiento

Suponga ahora que una empresa da descuentos a sus clientes de acuerdo a la cantidad de artı́culos
ordenados. El cuadro 1 muestra el descuento ofrecido dependiendo de la cantidad ordenada.

Una opción de programación ineficiente es crear un arreglo simple para guardar los descuentos. Se
podrı́a usar una variable llamada cantArts como subı́ndice en el arreglo, pero el arreglo podrı́a
requerir cientos de entradas, como se muestra enseguida:

12
Cantidad ordenada Descuento
1 a 12 Ninguno
13 a 49 10 %
50 a 99 14 %
100 a 199 18 %
200 o más 20 %

Cuadro 1: Tabla de descuentos

double [] descuentos = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0.10, 0.10, 0.10, ...};

En el arreglo descuentos se requieren trece ceros, porque el primer elemento del arreglo tiene un
subı́ndice cero y representa un descuento de cero para cero artı́culos y los siguientes 12 descuentos
también son cero para manejar desde un artı́culo hasta 12. Después el arreglo guardará 37 copias
de 0.10 para 13 artı́culos y hasta 49. El arreglo será necesariamente grande para guardar un valor
exacto para cada posible cantidad ordenada.

Una mejor opción es crear dos arreglos correspondientes y realizar un apareamiento de rango, en
el cual se compara un valor con los extremos de los rangos numéricos para encontrar la categorı́a a
la cual el valor pertenece. Por ejemplo, un arreglo puede tener los cinco descuentos, y el otro arreglo
puede tener los cinco lı́mites inferiores de los rangos de descuento, como se muestra enseguida:

int [] limitesInferiores = {1, 13, 50, 100, 200};


double [] descuentos = {0, 0.1, 0.14, 0.18, 0.2};

Empezando con el último elemento del arreglo limitesInferiores, para cualquier cantOrdenada
mayor que, o igual a limitesInferiores[4], el descuento es descuentos[4]. Si cantOrdenada
es menor que limitesInferiores[4], se deberá decrementar el subı́ndice y buscar en un rango
inferior. En la aplicación EncontrarDescuento, código 4, se muestra el uso de los arreglos paralelos
anteriores.
1 import j a v a x . swing . JOptionPane ;
2 public c l a s s E n c o n t r a r D e s c u e n t o {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 f i n a l int CANT RANGOS = 5 ;
5 int [ ] l i m i t e s I n f e r i o r e s = { 1, 13 , 50 , 100 , 200};
6 double [ ] d e s c u e n t o s = { 0 , 0 . 1 , 0 . 1 4 , 0 . 1 8 , 0 . 2 } ;
7 double d e s c u e n t o C l i e n t e ;
8 S t r i n g strCantOrdenada ;
9 int cantOrdenada ;
10 int sub = CANT RANGOS − 1 ;
11 strCantOrdenada = JOptionPane . s ho wI np ut Di al og ( null ,
12 ”¿Cuá n t o s a r tı́ c u l o s ha ordenado ? ” ) ;
13 cantOrdenada = I n t e g e r . p a r s e I n t ( strCantOrdenada ) ;
14 while ( sub >= 0 && cantOrdenada < l i m i t e s I n f e r i o r e s [ sub ] )
15 −−sub ;
16 d e s c u e n t o C l i e n t e = d e s c u e n t o s [ sub ] ;
17 JOptionPane . showMessageDialog ( null , ” El d e s c u e n t o para ” +

13
18 cantOrdenada + ” a r tı́ c u l o s e s ” + d e s c u e n t o C l i e n t e ) ;
19 }
20 }
Código 4: La aplicación EncontrarDescuento.

Nota. En la aplicación EncontrarDescuento, código 4, se require que sub sea mayor que, o igual
a cero antes de evaluar la expresión booleana cantOrdenada <limitesInferiores[sub]. Es un
buen hábito de programación asegurarse que un subı́ndice para un arreglo no caiga por debajo de
cero, ya que causará un error en tiempo de ejecución.

Actividad 5. Modificar la actividad 4 para permitir que se capturen varios equipos de baloncesto,
y después se le pida al usuario el nombre de algún equipo del que quiera ver sus jugadores.

6. Paso y devolución de arreglos en métodos

Se puede usar cualquier elemento de un arreglo de la misma forma como se usa cualquier variable
del mismo tipo. De igual forma, se puede pasar un elemento de un arreglo a un método de la misma
forma como se pasa una variable.

La aplicación PasarElementoArreglo, código 5, crea un arreglo de cuatro enteros y los muestra.


La aplicación llama el método obtenerUnEntero() cuatro veces, pasando un elemento a la vez.
El método muestra el número, cambia el número a 999, y luego muestra el número otra vez.
Finalmente, de regreso en el método main(), los cuatro números son mostrados otra vez.
1 import j a v a x . swing . JOptionPane ;
2 public c l a s s P a s a r E l e m e n t o A r r e g l o {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int [ ] numeros = { 1 0 , 2 0 , 3 0 , 4 0 } ;
5 System . out . p r i n t ( ” Al i n i c i o de main : ” ) ;
6 f o r ( int n : numeros )
7 System . out . p r i n t ( ” ” + n ) ;
8 System . out . p r i n t l n ( ) ;
9 f o r ( int i =0; i <numeros . l e n g t h ; ++i )
10 obtenerUnEntero ( numeros [ i ] ) ;
11 System . out . p r i n t ( ” Al f i n a l de main : ” ) ;
12 f o r ( int n : numeros )
13 System . out . p r i n t ( ” ” + n ) ;
14 System . out . p r i n t l n ( ) ;
15 }
16 public s t a t i c void obtenerUnEntero ( int uno ) {
17 System . out . p r i n t ( ” Al i n i c i o d e l método ((uno)) e s : ” + uno ) ;
18 uno = 9 9 9 ;
19 System . out . p r i n t l n ( ” y a l f i n a l d e l método ((uno)) e s : ” + uno ) ;
20 }
21 }
Código 5: La aplicación PasarElementoArreglo.

Al ejecutar la aplicación PasarElementoArreglo, se puede ver que los cuatro números pasados
fueron cambiados en el método obtenerUnEntero() permanecen sin cambio de regreso en main()

14
después de la ejecución del método. La variable llamada uno es local al método obtenerUnEntero,
y cualquier cambio a variables pasadas en el método no son permanentes y no son reflejados en el
arreglo en el método main(). Cada variable llamada uno en el método obtenerUnEntero guarda
una sola copia del elemento del arreglo pasado al método. Los elementos individuales del arreglo
son pasados por valor; es decir, una copia del valor es hecha y usada dentro del método receptor.
Cuando cualquier tipo primitivo, boolean, char, byte, short, int, long, float, o double, es
pasado a un método, el valor es pasado.

Los arreglos, como todos los objetos no primitivos, son tipos de referencia, esto es, el objeto
guarda una dirección de memoria donde los valores están guardados. Como un arreglo es una
referencia, no se puede asignar otro arreglo a este usando el operador =, ni se pueden comparar
dos arreglos usando el operador ==. Cuando se pasa un arreglo, se pasa su nombre, a un método,
el método receptor obtiene una copia de la dirección de memoria actual del arreglo. Por lo tanto el
método receptor tiene acceso a los valores originales del arreglo de elementos del método llamador.

La aplicación PasarArreglo, código 6, crea un arreglo de cuatro enteros. Después que los enteros son
mostrados, el nombre del arreglo, su dirección, es pasado a un método llamado obtieneArreglo().
Dentro del método, los números son mostrados, para observar que estos retienen sus valores des-
de main(), luego el valor 888 está asignado a cada número. A pesar de que obtieneArreglo()
es un método void, no devuelve nada al método main(), cuando el método main() muestra el
arreglo por segunda ocasión, todos los valores han sido cambiados a 888. Ejecutar la aplicación
PasarArreglo para comprobar lo comentado. Como el método recibe una referencia del arreglo, el
método obtieneArreglo() “sabe” la dirección del arreglo declarado en main() y hace sus cambios
directamente al arreglo original.
1 import j a v a x . swing . JOptionPane ;
2 public c l a s s P a s a r A r r e g l o {
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
4 int [ ] numeros = { 1 0 , 2 0 , 3 0 , 4 0 } ;
5 System . out . p r i n t ( ” Al i n i c i o de main : ” ) ;
6 f o r ( int n : numeros )
7 System . out . p r i n t ( ” ” + n ) ;
8 System . out . p r i n t l n ( ) ;
9 o b t i e n e A r r e g l o ( numeros ) ;
10 System . out . p r i n t ( ” Al f i n a l de main : ” ) ;
11 f o r ( int n : numeros )
12 System . out . p r i n t ( ” ” + n ) ;
13 System . out . p r i n t l n ( ) ;
14 }
15 public s t a t i c void o b t i e n e A r r e g l o ( int [ ] a r r ) {
16 System . out . p r i n t ( ” Al i n i c i o d e l método a r r t i e n e : ” ) ;
17 f o r ( int n : a r r )
18 System . out . p r i n t ( ” ” + n ) ;
19 System . out . p r i n t l n ( ) ;
20 f o r ( int i =0; i <a r r . l e n g t h ; ++i )
21 arr [ i ] = 888;
22 System . out . p r i n t ( ” Al f i n a l d e l método a r r t i e n e : ” ) ;
23 f o r ( int n : a r r )
24 System . out . p r i n t ( ” ” + n ) ;
25 System . out . p r i n t l n ( ) ;
26 }
27 }

15
Código 6: La aplicación PasarArreglo.

Nota. En otros lenguajes, como C, C++, y C#, se puede escoger pasar variables a métodos por
valor o referencia. No se puede escoger en Java. Las variables tipo primitivo son siempre pasadas
por valor. Cuando se pasa un objeto, una copia de la referencia al objeto es siempre pasada.

Regresar un arreglo desde un método

Un método puede regresar una referencia arreglo. Cuando un método regresa una referencia arreglo,
se deben incluir corchetes con el tipo regresado en la cabecera del método. En el siguiente código se
muestra el método getArreglo() que regresa un arreglo de int declarado localmente. Los corchetes
son usados como parte del tipo regresado; la sentencia return devuelve el nombre del arreglo sin
ningún corchetes.

public static int [] getArreglo() {


int [] puntuaciones = {98, 74, 69, 89};
return puntuaciones;
}

Cuando se llama al método getArreglo() que se muestra previamente, se puede guardar su valor
devuelto en cualquier referencia arreglo entero. Por ejemplo, se podrı́a declarar un arreglo y hacer
la llamada del método en la siguiente sentencia:

int [] puntuacionesRecibidas = getArreglo();

Actividad 6. Agregar a la actividad 5 un método que devuelva un arreglo de 5 equipos de ba-


loncesto. En el método se pedirá el nombre del equipo y los nombres de los jugadores para cada
uno de los equipos. Agregar en el método main() la llamada a este método que crea los equipos de
baloncesto.

16

También podría gustarte