2011-04-01 91 views
6

我傳遞了一個對象集合(在我的情況下是一些Contact類),並且需要從該集合中返回一個頁面。 我的代碼感覺比需要的時間長得多。我是否錯過了一些可以執行更優雅的庫,而不是像以下那樣遍歷每個元素?如何從集合中返回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

集合是如何消耗的?你使用什麼方法/計劃使用它? – Carl 2011-04-01 16:21:57

回答

11

你可以使用番石榴Iterables.partition

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

一個更復雜的版本不創建的所有頁面,以選擇一個正確的,但在右頁中找到停止。

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 
} 

更新:

由於ColinD指出:

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

是一個簡單的實現。

+0

如果'x'已經是'List',那麼使用'Lists.partition'代替它會更好。如果參數在OP中是一個'Collection',那麼它仍然值得檢查一下,如果這個集合是'List'並且可能的話使用'Lists'。 – ColinD 2011-04-01 16:30:19

+0

我會爲列表實現一個方法。只有在靜態類型信息丟失並且性能至關重要時,我纔會在上面的方法中添加檢查。根據情況,最好在調用者中進行強制轉換並直接調用列表版本。 – 2011-04-01 16:53:10

+0

是的,只需要使用一個需要'List'的重載就可以了。 – ColinD 2011-04-01 16:56:30

4

你的元素,你應該使用List,而不是一個collectionListCollection之間的基本區別在於List對元素具有固定的順序。它還定義了非常方便的方法subList(int start, int end),它創建了一個子列表,它是原始列表的別名,只包含您想要的元素,而不需要將它們複製到新列表的開銷。

+0

然而意圖可能能夠與任何類型的集合一起使用,特別是與列表和集合一起使用。集合似乎是一個合理的候選人,因爲聯繫人可能需要排除重複。 – iainmcgin 2011-04-01 16:16:12

+0

@iainmcgin,集合沒有排序或索引。如果你想在一個Set上翻頁,你可以把它的一個副本放到一個List中。 – 2011-04-01 16:26:27

+0

@Peter TreeSet(更一般地說,SortedSet實現)是基於實現Comparable的實例或提供的Comparator實例進行排序的,LinkedHashSet具有基於事件添加到集合的順序的順序。然後基於這個順序隱含元素的索引,所以期望能夠遍歷它們仍然是合理的。這些是我特意想到的情況,對於不預先說明這一點表示歉意。 – iainmcgin 2011-04-01 16:32:26

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

注:這將返回子表獨家是以lastElement

注2:結果被複制到另一個列表由凱文提到的原因。

6

如果你能要求的數據分頁到是List,你可以很容易地使用Guava獲取單個頁面的子列表視圖:

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

這不涉及複製或迭代(它使用的子表意見的原始列表),並處理透明地具有少於pageSize元素的最終頁面。

對於任意IterableCollection,我應該這樣做:

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

通過提供這兩種方法,你就能夠處理已知被有效地在編譯時列出的對象和任何其他類型的Iterable儘可能高效。

+0

我認爲這個版本對於LinkedLists比Iterable版本慢。 LinkedLists的subList實現是O(n)(它使用get(int),它是O(n))。您應該添加一個檢查List實現RandomAccess,併爲不包含List的Iterable版本添加。 – 2011-04-01 17:25:56

+0

@Thomas:這取決於你將如何使用返回的頁面List。如果你打算做基於索引的訪問,最好使用'Iterable'版本......或者在使用它之前將分區複製到'RandomAccess'列表中。我認爲在很多情況下,頁面列表可能只是被迭代,在這種情況下,它應該是原樣。 – ColinD 2011-04-01 18:51:57

0
Iterables.partition(contacts, pageSize).forEachRemaining(paginatedContacts->{/*Operation here*/}); 
相關問題