FUNDAMENTOS DE PROGRAMACIÓN Versión: 0.0.2 Tema 4. Colecciones I Autor: Miguel Toro Bonilla Revisión: José C. Riquelme Adaptación a FP: Carlos A. García Vallejo Tiempo estimado: 2 horas 1. Introducción ................................................................................................................................................ 1 2. La interfaz Collection................................................................................................................................... 1 3. El tipo List .................................................................................................................................................... 3 4. El tipo Set .................................................................................................................................................... 6 5. El tipo SortedSet.......................................................................................................................................... 7 6. La clase de utilidad Collections ................................................................................................................. 11 7. Ejercicios.................................................................................................................................................... 14 1. Introducción En el tema 2 se han visto las listas (interfaz List). Como se ha explicado, son secuencias de elementos que se pueden indexar, de modo que el primer elemento es el 0, el siguiente el 1, etc. hasta llegar al último elemento, que ocupa la posición size() – 1 (recordemos que size() es una operación que devuelve el número de elementos de la lista. La adecuada utilización de tipos de datos agregados predefinidos en la API de Java, como el tipo List, simplifica mucho el desarrollo de programas correctos en Java y tiene muchas otras ventajas: Reduce el esfuerzo de programación puesto que proporciona estructuras de datos y algoritmos útiles. Incrementa la velocidad y la calidad de los programas, puesto que Java ofrece implementaciones optimizadas y libres de errores. Simplifica la interoperabilidad y la reemplazabilidad entre aplicaciones, puesto que facilita estructuras que se pueden intercambiar entre distintos componentes. Reduce esfuerzos de aprendizaje y diseño. En este capítulo vamos a ver las colecciones, modeladas mediante la interfaz Collection y dos de las interfaces que heredan de ella: List, que modela las listas, y Set, que modela los conjuntos. Finalizaremos viendo la clase de utilidad Collections, que permite realizar operaciones sobre las colecciones. 2. La interfaz Collection La interfaz Collection, que define un tipo que podemos denominar Colección, está definida en el paquete java.util. Una colección es un tipo muy general, que agrupa objetos (elementos) de un mismo tipo; su 2 Fundamentos de Programación comportamiento específico viene determinado por sus subinterfaces, que pueden admitir elementos duplicados o no, y cuyos elementos pueden estar ordenados o no según determinado criterio. No existe una implementación específica de la interfaz Collection; sí la tienen sus subinterfaces. El tipo Collection se utiliza para declarar variables o parámetros donde se quiere la máxima generalidad posible, esto es, que puedan ser utilizados tanto por listas como por conjuntos (Collection tiene otros subtipos que se tratarán más adelante). La interfaz Collection es genérica, por lo que hablaremos de Collection<E> (como se vio en el tema 2). Hereda de Iterable<E>, lo que implica que las colecciones, así como las listas y los conjuntos, subtipos suyos, son iterables y se puede utilizar con ellas el for extendido. La jerarquía de interfaces se representa en la Figura 1. <<interfaz>> Iterable<E> <<interfaz>> Collection<E> <<interfaz>> List<E> ...... <<interfaz>> Set<E> Figura 1. Jerarquía de tipos: Iterable, Collection, List y Set Las operaciones del tipo Collection se especifican a continuación1. En general, el valor devuelto por los métodos que devuelven boolean será true si la colección queda modificada por la aplicación del método y false en caso contrario. boolean add(E e) Añade un elemento a la colección, devuelve false si no se añade. boolean addAll(Collection<? extends E> c) Añade todos los elementos de c a la colección que invoca. Es el operador unión. Devuelve true si la colección original se modifica. void clear() Borra todos los elementos de la colección. boolean contains(Object o) Devuelve true si o está en la colección invocante. boolean containsAll(Collection<?> c) Devuelve true si la colección que invoca contiene todos los elementos de c. boolean isEmpty() Devuelve true si la colección no tiene elementos. 1 Puede obtener más información de la interfaz Collection en la documentación de la API de Java: http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html 4. Colecciones boolean remove(Object o) Borra el objeto o de la colección que invoca; si no estuviera se devuelve false. boolean removeAll(Collection<?> c) Borra todos los objetos de la colección que invoca que estén en c. Devuelve true si la colección original se modifica. boolean retainAll(Collection<?> c) En la colección que invoca sólo se quedarán aquellos objetos que están en c. Por tanto, es la intersección entre ambas colecciones. Devuelve true si la colección original se modifica. int size() Devuelve el número de elementos. T[] toArray(T[] a) Devuelve un array con la colección. 3. El tipo List Conceptualmente, las listas representan colecciones de elementos en los que importa cuál es el primero, el segundo, etc. Cada elemento está referenciado mediante un índice; el índice del primer elemento es el 0. Las listas pueden contener elementos duplicados. Desde el punto de vista de la API de Java, las listas son un subtipo de Collection: la interfaz List hereda de la interfaz Collection. Por tanto, tienen todas las operaciones vistas en el apartado anterior, aunque debemos prestar atención a la semántica de algunas operaciones: La operación addAll añade los elementos de la lista que se pasa al final de la lista sobre la que se invoca. Si en la lista sobre la que se invoca hay elementos duplicados, la operación removeAll elimina de esta todas las instancias de los elementos que aparecen en la lista que se pasa. De manera análoga se comporta retainAll: si en la lista sobre la que se invoca un elemento aparece n veces, y este aparece en la lista que se pasa (independientemente del número de veces que aparezca), en la lista resultado permanecerán las n apariciones del elemento. Todo esto se ilustra en el Ejemplo 1: Ejemplo 1. Ejemplo de comportamiento de removeAll y retainAll Si se ejecuta el siguiente código: List<String> l1 = new LinkedList<String>(); List<String> l2 = new LinkedList<String>(); l1.add("A"); l1.add("B"); l1.add("C"); l2.add("B"); l2.add("B"); l1.removeAll(l2); mostrar("l1 después de l1.removeAll(l2): ", l1); l1.add("A"); l1.add("B"); l1.add("C"); l2.add("B"); l2.add("B"); l2.removeAll(l1); 3 4 Fundamentos de Programación mostrar("l2 después de l2.removeAll(l1): ", l2); l1.add("A"); l1.add("B"); l1.add("C"); l2.add("B"); l2.add("B"); l2.retainAll(l1); mostrar("l2 después de l2.retainAll(l1): ", l2); se obtiene como salida: l1 después de l1.removeAll(l2): [A, C] l2 después de l2.removeAll(l1): [] l2 después de l2.retainAll(l1): [B, B] La interfaz List2 aporta varias operaciones específicas, que no aparecen en Collection; en las operaciones que tienen índice, si no se cumple la restricción sobre este se eleva la excepción IndexOutOfBoundsException. void add(int index, E element) Inserta el elemento especificado en la posición especificada. El que estaba previamente en la posición index pasará a la posición index + 1, el que estaba en la posición index + 1 pasará a la posición index + 2, etc. Los valores lícitos para index son 0 ≤ index ≤ size(). boolean addAll(int index, Collection<? extends E> c) Inserta todos los elementos de c en la posición especificada, desplazando el que estaba previamente en la posición index a la posición index + c.size(), etc. Los valores lícitos para index son 0 ≤ index ≤ size(). E get(int index) Devuelve el elemento de la lista en la posición especificada. Los valores lícitos para index son 0 index < size(). int indexOf(Object o) Devuelve el índice donde ser encuentra por primera vez el elemento o (si no está devuelve int -1). lastIndexOf(Object o) Devuelve el índice donde ser encuentra por última vez el elemento o (si no estuviera devuelve E -1). remove(int index) Borra el elemento de la posición especificada. Los valores lícitos para index son 0 size(). E ≤ ≤ index < set(int index, E element) Remplaza el elemento de la posición indicada por el que se da como argumento. Los valores lícitos para index son 0 ≤ index < size(). List<E> subList(int fromIndex, int toIndex) Devuelve una vista de la porción de la lista entre fromIndex, inclusive, and toIndex, sin incluir. Los valores lícitos de fromIndex y toIndex son 0 ≤ fromIndex ≤ toIndex ≤ size(). 2 Puede encontrarse más información en http://docs.oracle.com/javase/7/docs/api/java/util/List.html. 4. Colecciones La operación subList devuelve una vista de la lista original. Esto quiere decir que las operaciones que se realicen sobre la sublista se verán reflejadas en la lista original y viceversa. Hay que prestar atención al hecho de que si se produce un cambio estructural que afecte al tamaño de la lista original, pueden ocurrir comportamientos extraños, en particular la elevación de una excepción cuando se utiliza la sublista. El comportamiento de subList se puede ver en los Ejemplos 2 y 3. Ejemplo 2. Ejemplo de uso de subList Si se ejecuta el código: List<String> ls = new LinkedList<String>(); ls.add("A"); ls.add("B"); ls.add("C"); ls.add("D"); ls.add("E"); List<String> subLs = ls.subList(1, 4); mostrar("Sublista: ", subLs); ls.set(2, "F"); mostrar("Sublista después de modificar el elemento 2 de la lista: ", subLs); subLs.remove(1); mostrar("Sublista después de eliminar el elemento 1: ", subLs); mostrar("Lista original después de modificar la sublista: ", ls); subLs.add("X"); subLs.add("Y"); // añade "X" e "Y" al final de la sublista mostrar("Sublista después de añadirle X e Y: ", subLs); mostrar("Lista después de la modificación de la sublista: ", ls); ls.remove(0); mostrar("Lista después de eliminar el primer elemento: ", ls); mostrar("Sublista después de modificar la lista: ", subLs); Se obtiene como salida: Sublista: [B, C, D] Sublista después de modificar el elemento 2 de la lista: [B, F, D] Sublista después de eliminar el elemento 1: [B, D] Lista original después de modificar la sublista: [A, B, D, E] Sublista después de añadirle X e Y: [B, D, X, Y] Lista después de la modificación de la sublista: [A, B, D, X, Y, E] Lista después de eliminar el primer elemento: [B, D, X, Y, E] Ejemplo 3. Ejemplo de uso de subList con modificación de la lista original Si se ejectuta el código: List<String> ls = new LinkedList<String>(); ls.add("A"); ls.add("B"); ls.add("C"); ls.add("D"); ls.add("E"); List<String> subLs = ls.subList(1, 4); mostrar("Sublista: ", subLs); ls.remove(2); mostrar("Sublista después de modificar la lista: ", subLs); Se obtiene como salida: Exception in thread "main" java.util.ConcurrentModificationException 5 6 Fundamentos de Programación Las implementaciones de las listas son ArrayList y LinkedList3. La elección de una u otra implementación dependerá del tipo de operaciones que realicemos sobre ellas. Si se va a acceder preferentemente a los elementos mediante índice o a realizar búsquedas, debe usarse ArrayList. Si preferentemente se van a realizar operaciones de inserción o borrado al principio o al final debe usarse LinkedList. Esto se estudiará con más detalle en la asignatura ADDA de segundo curso. Las dos clases tienen dos constructores cada una: uno sin argumentos, que construye una lista vacía y otro que recibe una Collection y construye una lista con los elementos de la colección, en el orden en el que un for extendido devolvería sus elementos. 4. El tipo Set El tipo Set se corresponde con el concepto matemático de conjunto: un agregado de elementos en el que no hay orden (no se puede decir cuál es el 0, el 1, el 2, etc.) y donde no puede haber elementos repetidos. Dados dos conjuntos (de Integer) a y b: a = {1, 2, 3, 4} b = {4, 5, 6} recordemos que: a b = {1,2,3,4,5,6} a – b = {1,2,3} a b = {4} 1 6 4 3 2 a 5 b La interfaz Set4 no aporta ningún método extra a los que ya tiene Collection; por tanto, sus métodos son los de Collection y solo estos. Las operaciones addAll, retainAll y removeAll se pueden identificar con la unión, intersección y diferencia de conjuntos, respectivamente; la operación contains equivale a la pertenencia en conjuntos ( ); la operación containsAll se corresponde con la de subconjunto ( ). La implementación más habitual del tipo Set es la clase HashSet5. Tiene dos constructores: uno vacío, que construye un conjunto vacío, y otro que recibe una colección y construye un conjunto con los elementos de la colección (sin duplicados). El for extendido aplicado a un conjunto devuelve todos sus elementos en un orden que no es predecible. Hay una implementación, LinkedHashSet, en la que el for extendido devuelve los elementos en el orden en el que fueron insertados en el conjunto. 3 La información completa se puede encontrar en http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html y http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html). 4 Se puede encontrar más información en http://docs.oracle.com/javase/7/docs/api/java/util/Set.html. 5 Más información en http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html. 4. Colecciones Ejemplo 4. Orden en el que se itera sobre los elementos de un Set Si se ejecuta el código Set<Character> s = new HashSet<Character>(); s.add('A'); s.add('B'); s.add('P'); s.add('Q'); mostrar(s); s = new LinkedHashSet<Character>(); s.add('A'); s.add('B'); s.add('P'); s.add('Q'); mostrar(s); Se obtiene la salida [Q, P, A, B] [A, B, P, Q] 5. El tipo SortedSet El tipo SortedSet es un subtipo de los conjuntos (por tanto los elementos no están indexados y no puede haber elementos repetidos), en el que existe una relación de orden entre los elementos que permite decir cuál va antes y cuál después. Para simplificar hablaremos de menores o mayores, entendiendo que significa “va antes o después”, según el criterio de ordenación. A las operaciones de Set (a su vez las de Collection) añade estas otras: SortedSet<E> headSet(E toElement) Devuelve una vista de los elementos del SortedSet sobre el que se invoca con los elementos que son menores (van antes según el criterio de ordenación) que toElement, excluido. SortedSet<E> tailSet(E fromElement) Devuelve una vista con los elementos que son mayores que incluido este. SortedSet<E> fromElement, subSet(E fromElement, E toElement) Devuelve una vista con los elementos mayores que fromElement, incluido, y menores que toElement, excluido. Si toElement es posterior a fromElement, se eleva la excepción IllegalArgumentException. E first() Devuelve el primer elemento. Si el SortedSet está vacío eleva la excepción NoSuchElementException. E last() Devuelve el último elemento. Si el SortedSet está vacío eleva la excepción NoSuchElementException. 7 8 Fundamentos de Programación Comparator<? super E> comparator() Devuelve el orden del conjunto ordenado o natural de E. null si está ordenado por el orden Ejemplo 5. Ejemplo de uso de headSet, tailSet y subSet Si se ejecuta el código SortedSet<Character> ss = new TreeSet<Character>(); ss.add('X'); ss.add('C'); ss.add('F'); ss.add('P'); ss.add('R'); ss.add('Q'); mostrar("ss = " + ss); SortedSet<Character> inicio = ss.headSet('G'); SortedSet<Character> medio = ss.subSet('G', 'R'); SortedSet<Character> fin = ss.tailSet('Q'); mostrar("headSet('G') = " + inicio); mostrar("subSet('G', 'R') = " + medio); mostrar("tailSet('Q') = " + fin); Se obtiene la salida ss = [C, F, P, Q, R, X] headSet('G') = [C, F] subSet('G', 'R') = [P, Q] tailSet('Q') = [Q, R, X] Las operaciones sobre rangos devuelven vistas del conjunto ordenado original, de modo que si se actúa sobre el original se modifica la vista y viceversa. Ejemplo 6. Ejemplo que ilustra que los rangos son vistas del conjunto ordenado original Si se ejecuta el código mostrar("ss = " + ss); fin.add('S'); mostrar("tailSet('Q') tras add('S') = " + fin); mostrar("ss tras add('S') = " + ss); ss.add('D'); mostrar("ss tras add('D') = " + ss); mostrar("headSet('G') tras add('D') = " + inicio); Se obtiene como salida ss = [C, F, P, Q, R, X] tailSet('Q') tras add('S') = ss tras add('S') = [C, F, P, ss tras add('D') = [C, D, F, headSet('G') tras add('D') = [Q, R, S, X] Q, R, S, X] P, Q, R, S, X] [C, D, F] En las vistas devueltas por las operaciones con rangos solo se puede actuar sobre el rango delimitado por fromElement y toElement. 4. Colecciones Ejemplo 7. En las vistas de los SortedSet no se puede actuar fuera del rango Si se ejecuta inicio.add('G'); Se obtiene java.lang.IllegalArgumentException: key out of range La implementación de los conjuntos ordenados es la clase TreeSet6. Esta clase tiene cuatro constructores: Un constructor vacío, que crea un conjunto ordenado vacío donde los elementos se ordenaran según su orden natural (los elementos tienen que implementar Comparable). Un constructor con un argumento de tipo Collection, que crea un conjunto ordenado con los elementos de la colección ordenados según su orden natural (los elementos de la colección tienen que implementar Comparable). Un constructor que recibe un Comparator, que crea un conjunto ordenado vacío cuyos elementos se ordenaran según el orden inducido por el Comparator. Un constructor que recibe un SortedSet, que crea un conjunto ordenado con los mismos elementos que el que recibe como argumento y usando su mismo orden. El for extendido sobre los elementos de un SortedSet los devuelve en el orden que tienen inducido. Ejemplo 8. Orden en el que itera el for extendido sobre los elementos de un SortedSet El código SortedSet<Character> ss = new TreeSet<Character>(); ss.add('X'); ss.add('C'); ss.add('F'); ss.add('P'); ss.add('R'); ss.add('Q'); for (Character ch : ss) { mostrar(ch); } Provoca la siguiente salida: C F P Q R X Hay que hacer una observación sobre el uso de los conjuntos ordenados el que caso en el que tenga el orden inducido por un Comparator. El orden natural de los elementos tiene que ser compatible con la igualdad, esto es, para dos elementos a y b a.equals(b) == true, si y solo si a.compareTo(b) == 0. Sin embargo con un orden alternativo creado con un Comparator, compare(a, b) == 0 no implica necesariamente que a.equals(b) == true. Sin embargo, las implementaciones de los conjuntos ordenados insertan un elemento nuevo solo si su comparación con los existentes no es cero para ninguno de ellos. Si se está usando el orden natural, esto 6 La información completa se encuentra en http://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html. 9 10 Fundamentos de Programación equivale a que no hay un elemento igual que el nuevo, lo que coincide con la idea que tenemos de la inserción en conjuntos no ordenados; sin embargo, si se usa un orden alternativo puede que haya dos elementos distintos cuya comparación de 0, por lo que el segundo no se insertaría. Si este es el comportamiento deseado, no habría que hacer nada, pero si no lo es, la solución más sencilla es modificar la comparación entre elemento introduciendo un “desempate” por el orden natural en caso de que haya “empate” por el orden alternativo. Ejemplo 9. Orden natural y alternativos en un SortedSet Supongamos que tenemos un orden natural en la clase PersonaImpl que es apellidos, nombre, dni (con el que será compatible equals). Supongamos también que tenemos los comparadores: public class ComparadorPersonaEdad1 implements Comparator<Persona> { public int compare(Persona p1, Persona p2) { int cmp = p1.getEdad().compareTo(p2.getEdad()); return cmp; } } y public class ComparadorPersonaEdad2 implements Comparator<Persona> { public int compare(Persona p1, Persona p2) { int cmp = p1.getEdad().compareTo(p2.getEdad()); if (cmp == 0) { cmp = p1.compareTo(p2); } return cmp; } } Si se ejecuta el siguiente código Persona p1 = new PersonaImpl("31122334-W", "Antonio", "García Maratón", 22); Persona p2 = new PersonaImpl("34423123-V", "María", "Pérez Piña", 20); Persona p3 = new PersonaImpl("38962334-W", "Eva", "García Morón", 22); Persona p4 = new PersonaImpl("34435723-V", "Eugenia", "Gómez Titos", 20); SortedSet<Persona> ss = new TreeSet<Persona>(); ss.add(p1); ss.add(p2); ss.add(p3); ss.add(p4); mostrar("ss con el orden natural (apellidos, nombre, dni):\n", ss); Se obtiene la salida ss con el orden natural (apellidos, nombre, dni): [García Maratón, Antonio (31122334-W), García Morón, Eva (38962334-W), Gómez Titos, Eugenia (34435723-V), Pérez Piña, María (34423123-V)] Si a continuación se ejecuta ss = new TreeSet<Persona>(new ComparadorPersonaEdad1()); ss.add(p1); ss.add(p2); ss.add(p3); ss.add(p4); mostrar("ss con el orden por edad sin desemapate:\n", ss); Se obtiene la salida ss con el orden por edad sin desemapate: [Pérez Piña, María (34423123-V), García Maratón, Antonio (31122334-W)] Vemos que se han “perdido” dos personas, que tenían 20 y 22 años, como las dos que aparecen. Finalmente, si se ejecuta ss = new TreeSet<Persona>(new ComparadorPersonaEdad2()); ss.add(p1); ss.add(p2); ss.add(p3); ss.add(p4); mostrar("ss con el orden por edad sin desempate:\n", ss); 4. Colecciones Se obtiene la salida ss con el orden por edad sin desempate: [Gómez Titos, Eugenia (34435723-V), Pérez Piña, María (34423123-V), García Maratón, Antonio (31122334-W), García Morón, Eva (38962334-W)] donde están todas las personas, están en orden de edad y dentro de los de la misma edad, en orden alfabético de apellidos, nombre. 6. La clase de utilidad Collections El paquete java.util contiene la clase de utilidad Collections7. Esta clase está formada por métodos estáticos que permiten realizar operaciones sofisticadas sobre las colecciones, como invertir una lista, barajarla, ordenarla, buscar una sublista dentro de una lista, encontrar el máximo o el mínimo de los elementos de una colección, contar las veces en las que aparece un elemento, etc. Algunos de sus métodos (los más usados) son: static <T> boolean addAll(Collection<? super T> c, T... elements) Añade a la colección los elementos indicados en elements. static <T> int binarySearch(List<? extends super T>> list, T key) Devuelve la posición del objeto Comparable<? key en la lista ordenada según su orden natural, o -1 si no lo encuentra. static <T> int binarySearch(List<? extends Comparator<? super T> c) Devuelve la posición del objeto T> list,T key, key en la lista ordenada según el orden c, o -1 si no lo encuentra. public static <T> void copy(List<? super T> dest, List<? extends T> src) Copia los elementos de la lista src en la lista dest, en el mismo orden en el que se encuentran. La lista de dest debe tener al menos tantos elementos como la lista src; en caso contrario eleva la excepción IndexOutOfBoundsException. Si la lista dest tiene más elementos que src, los elementos restantes de dest permanecen inalterados. static boolean disjoint(Collection<?> c1, Collection<?> c2) Devuelve verdadero si no hay elementos comunes a las dos colecciones. static void fill(List<? super T> l, T o) Reemplaza todos los elementos de la lista l por o. 7 Se puede encontrar una descripción exhaustiva en http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html. 11 12 Fundamentos de Programación static int frequency(Collection<?> coll, Object o) Devuelve el número de elementos iguales a static int o en la colección coll. indexOfSubList(List<?> source, List<?> target) Devuelve la primera posición de la primera ocurrencia de target dentro de source, o -1 si no encuentra ninguna. static int lastIndexOfSubList(List<?> source, List<?> target) Devuelve la primera posición de la última ocurrencia de target dentro de source o -1 si no encuentra ninguna. static <T max(Collection<? extends T> coll) extends Object & Comparable Devuelve el elemento máximo de la colección coll según el orden natural de sus elementos. <? super T>> T static <T> T max(Collection<? extends T> coll, Comparator<? super T> c) Devuelve el element máximo de la colección coll según el orden dado por el Comparator c. static <T extends Object min(Collection<? extends T> coll) & Comparable<? super T>> T Devuelve el elemento mínimo de la colección natural de sus elementos. static <T> T min(Collection<? extends T> coll, coll según el orden Comparator<? super T> c) Devuelve el element mínimo de la colección coll según el orden dado por el Comparator c. static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) Reemplaza en list el objeto oldVal por newVal. static void reverse(List<?> list) Invierte los elementos de la lista static void list. rotate(List<?> list, int distance) Rota la lista en un número distance de casillas hacia la derecha si es positivo o hacia la izquierda si es negativo. static <T extends sort(List<T> list) Comparable<? super T>> Ordena la lista según el orden natural del tipo. void static <T> void sort(List<T> list, Comparator<? super T> c) Ordena la lista según el orden dado por c. 4. Colecciones Ejemplo 10. Utilización de la clase Collections Si se ejecuta el código List<String> l = new LinkedList<String>(); l.add("R"); l.add("T"); l.add("B"); l.add("A"); l.add("M"); mostrar(l); Collections.reverse(l); mostrar(l); Collections.sort(l); mostrar(l); mostrar(Collections.frequency(l, "B")); Collections.fill(l, "X"); mostrar(l); La salida será: [R, [M, [A, 1 [X, T, B, A, M] A, B, T, R] B, M, R, T] X, X, X, X] 13 14 Fundamentos de Programación 7. Ejercicios Ejercicio 1 Escriba la clase TestEjercicio1 con un método main que a) Cree dos conjuntos vacíos de Integer, añada al primero 7, 3, 9, 1, 5, 3 y al segundo 1, 2, 3, 4 y los muestre por pantalla. b) Muestre el cardinal de cada uno de los conjuntos. c) Pregunte si uno de los conjuntos contiene un entero dado que está y uno que no está. d) Añada un entero al primer conjunto, compruebe el valor devuelto por la operación dependiendo de si el entero estaba ya en el conjunto o no y muestre el conjunto resultante. e) Elimine un entero de uno de los conjuntos. Muestre el resultado. f) Calcule la unión, la intersección y la diferencia de los conjuntos y muestre los resultados. Ejercicio 2 Escriba la clase TestEjercicio2 con un método main que a) Cree dos listas vacías de Character, añada a la primera ‘S’, ‘E’, ‘M’, ‘A’, ‘N’, ‘A’ y a la segunda ‘R’, ‘A’, ‘M’, ‘O’ y las muestre por pantalla. b) Muestre el cardinal de cada una de las listas. c) Pregunte si una de las listas contiene una letra dada. d) Pregunte en qué posición está una letra que sí está en una lista y otra que no está. e) Añada al final de la primera lista ‘S’, compruebe el valor devuelto por la operación y muestre la lista resultante. f) Obtenga la sublista definida por dos posiciones, que incluya el último elemento. g) Elimine todos los elementos de una lista entre dos posiciones dadas y muestre el resultado. h) Ordene la lista según el orden natural y muéstrela i) Calcule la unión, la intersección y la diferencia de las listas dadas y muestre los resultados. Observe qué diferencia hay con estas operaciones para conjuntos. j) Invierta la lista y muéstrela. Nota: Siempre debemos actuar sobre las listas o los conjuntos originales. Para ello creamos dos estructuras originales y, en aquellos apartados en los que se modifica la estructura, creamos copias. Para copiar el contenido de una lista o un conjunto se usa el constructor copia. Es un constructor que tiene como argumento la lista o conjunto que se desea copiar. Por ejemplo: List<Integer> copia = new ArrayList<Integer>(original) copia los elementos de la lista original en una nueva lista copia. 4. Colecciones Anexo: Métodos de las interfaces Collection, List, Set, SortedSet y clase de utilidad Collections. public interface Collection<T> extends public interface SortedSet<T> extends Set<T> { Iterable<T> { T first(); int size(); T last(); boolean isEmpty(); SortedSet<T> headSet(T toElement); boolean contains(Object element); SortedSet<T> tailSet(T fromElement); boolean add(T element); SortedSet<T> subSet(T fromElement , boolean remove(Object element); T toElement); boolean containsAll(Collection<?> c); Compartor<? Super T> compartor(); boolean addAll(Collection<? extends T> c); } boolean removeAll(Collection<?> c); public interface List<T> extends Collection<T> { boolean retainAll(Collection<?> c); T get(int index); void clear(); T set(int index, T element); <T> T[] toArray(T[] a); void add(int index, T element); } boolean remove(int index); public interface Set<T> extends Collection<T> boolean addAll(int index, { Collection<? extends T> c); } int indexOf(Object o); int lastIndexOf(Object o); List<T> subList(int fromIndex, int toIndex); } public class Collections { public static <T> boolean addAll(Collection<? super T> c, T... elements); public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key); public static <T> int binarySearch(List<? extends T> list,T key, Comparator<? super T> c); public static void copy (List<? super T> dest, List<? extends T> src); public static boolean disjoint(Collection<?> c1, Collection<?> c2); public static void fill (List<? super T> l, T o); public static int frequency (Collection<?> c, Object o); public static int indexOfSubList(List<?> source, List<?> target); public static int lastIndexOfSubList(List<?> source, List<?> target); public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll); public static <T> T max(Collection<? extends T> coll, Comparator<? super T> c); public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll); public static <T> T min(Collection<? extends T> coll, Comparator<? super T> c); public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal); public static void reverse (List<T> list); public static void rotate(List<?> list, int distance); public static void <T extends Comparable<? super T>> sort ( List<T> l); public static void sort ( List<T> l, Comparator<? super T> c); } 15