2011-04-01 22 views
6

Tengo una colección de objetos (algunos clase de contacto en mi caso) y necesito devolver una página de esa colección. Mi código parece mucho más largo de lo necesario. ¿Me faltan algunas bibliotecas que podrían realizar eso de forma más elegante que iterar sobre cada elemento uno a la vez como hago abajo?Cómo devolver N elementos consecutivos de una Colección?

protected Collection<Contact> getPageOfContacts(
    Collection<Contact> contacts, int pageIndex, int pageSize) { 
    if (pageIndex < 0 || pageSize <= 0 
    || pageSize > contacts.size()) { 
    return contacts; 
    } 
    int firstElement = pageIndex * pageSize; 
    int lastElement = (pageIndex + 1) * pageSize - 1; 
    Collection<Contact> pagedContacts = new ArrayList<Contact>(); 
    int index = -1; 
    for (Contact contact : contacts) { 
    index++; 
    if (index < firstElement) { 
     continue; 
    } 
    if (index > lastElement) { 
     break; 
    } 
    pagedContacts.add(contact); 
    } 
    return pagedContacts; 
} 
+0

¿Cómo se consume la colección? ¿Qué métodos está usando/plan para usar en él? – Carl

Respuesta

11

Usted podría utilizar guayaba Iterables.partition:

protected <T> Collection<T> getPageOfContacts(
     Collection<T> contacts, int pageIndex, int pageSize) { 
    return Lists.newArrayList(
     Iterables.partition(contacts, pageSize)).get(pageIndex); 
} 

Una versión más compleja no crea todas las páginas para elegir el más adecuado, pero se detiene cuando se encuentra la página de la derecha.

protected <T> Collection<T> getPageOfContacts(
     Collection<T> contacts, int pageIndex, int pageSize) { 
    Iterator<List<T>> partitions = Iterators.partition(contacts.iterator(), pageSize); 

    for(int page = 0; page<pageSize && partitions.hasNext(); page++){ 
     List<T> partition = partitions.next(); 
     if(page == pageIndex) return partition; 
    } 
    return Collections. <T> emptyList(); //or fail 
} 

Actualización:

Gracias a ColinD señalar que:

Iterables.get(Iterables.partition(contacts, pageSize), pageIndex) 

es una aplicación simple.

+0

Si 'x' ya es una' Lista', sería mucho mejor usar 'Lists.partition' en su lugar. Con el parámetro siendo una 'Colección' como en el OP, aún vale la pena verificar si la colección es una 'Lista' y usar 'Listas' si es posible. – ColinD

+0

Implementaré un método para listas. Solo si falta la información del tipo estático y el rendimiento es crítico, agregaría la verificación en el método anterior. Dependiendo de la situación, puede ser mejor hacer el reparto en la persona que llama y llamar a la versión de la lista directamente. –

+0

Sí, tendría sentido usar una sobrecarga que tome una 'Lista 'en su lugar. – ColinD

4

Si quieres un orden definido a sus elementos, usted debe utilizar un List, no un collection. La diferencia básica entre List y Collection es que List tiene un orden fijo a los elementos. También define el método muy conveniente subList(int start, int end) que crea una sublista que es un alias de la lista original que contiene solo los elementos que desea sin la sobrecarga de copiarlos en una nueva lista.

+0

Sin embargo, la intención puede ser poder trabajar con cualquier tipo de colección, en particular con listas y conjuntos. Los conjuntos parecen ser un candidato razonable, ya que es probable que los contactos se ordenen con la necesidad de eliminar duplicados. – iainmcgin

+0

@iainmcgin, los conjuntos no están ordenados ni indexados. Si desea enviar una página a través de un conjunto, puede tomar una copia de ella en una lista. –

+0

@Peter TreeSet (y, en general, implementaciones SortedSet) se ordenan en función de los elementos que implementan Comparable o una instancia de Comparator proporcionada, y LinkedHashSet tiene un orden basado en el orden en que se agregan las cosas al conjunto. Los índices de los elementos están implícitos según este orden, por lo que es razonable esperar poder navegar a través de ellos. Estos fueron los casos en los que estaba pensando específicamente, disculpas por no mencionar esto por adelantado. – iainmcgin

0
return new ArrayList<Contact>(new ArrayList<Contact>(contacts).subList(firstElement, lastElement)); 

Nota: esto devolverá la lista secundaria exclusiva lastElement

Nota 2: El resultado se copian en otra lista, por las razones mencionadas por Kevin.

6

Si puede requerir que los datos pueden ser llamados a ser un List, se puede obtener una vista de lista secundaria de una sola página fácilmente usando Guava:

public <T> List<T> getPage(List<T> list, int pageIndex, int pageSize) { 
    return Lists.partition(list, pageSize).get(pageIndex); 
} 

Esto implica ninguna copia o iteración (que utiliza vistas sublista de la lista original) y maneja una página final que tiene menos de pageSize elementos de forma transparente.

Para una arbitraria Iterable o Collection, me gustaría hacer esto:

public <T> List<T> getPage(Iterable<T> iterable, int pageIndex, int pageSize) { 
    return Iterables.get(Iterables.partition(iterable, pageSize), pageIndex); 
} 

Al proporcionar estos dos métodos, que sería capaz de manejar objetos que se sabe que son listas en tiempo de compilación y eficiente cualquier otro tipo de Iterable tan eficientemente como sea posible.

+0

Creo que esta versión es más lenta para LinkedLists que la versión Iterable. La implementación de subList para LinkedLists es O (n) (usa get (int) que es O (n)). Debería agregar una comprobación de que la Lista implementa RandomAccess y agregar una versión Iterable para las listas que no lo hacen. –

+0

@Thomas: depende de cómo va a utilizar la página 'List' que se devuelve. Si vas a tener acceso basado en índices, es mejor que uses la versión 'Iterable' ... o copiando la partición en una lista' RandomAccess' antes de usarla. Creo que en muchos casos la lista de páginas podría repetirse, en cuyo caso debería estar bien tal como está. – ColinD

0
Iterables.partition(contacts, pageSize).forEachRemaining(paginatedContacts->{/*Operation here*/}); 
Cuestiones relacionadas