HiveBrain v1.2.0
Get Started
← Back to all entries
snippetpythonMinor

how to generate numbers for pagination?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
paginationnumbersgenerateforhow

Problem

I made a function that returns the number displayed for pagination. I want to get something like this (parentheses is the only show where the active site):

if pages 10

1 2 3 ... 20 [30] 40 ... 78 79 80


where [30] is active page. If active page < 3

1 2 [3] 4 ... 20 30 40 ... 78 79 80


etc. My code:

count_all - number of all items
    items_on_page - items displayed on one page
    page - current page

    countpages = int(float(count_all+(items_on_page-1))/float(items_on_page))
    linkitems = 10

    if countpages > (linkitems-1):
        countpagesstr = list()
        for i in range(1,int(float(linkitems+(2))/float(3))):
            countpagesstr += [str(i)]

        countpagesstr += ['...']
        sr = int(countpages/2)
        for i in range(sr-1, sr+1):
            countpagesstr += [str(i)]

        countpagesstr += ['...']
        for i in range(countpages-3, countpages):
            countpagesstr += [str(i)]
    else:
        cp = list()
        for c in range(1,countpages+1):
            cp.append(str(c))
        countpagesstr = cp

    return countpagesstr


How to do it better?

Solution

-
Your code doesn't run as written. It needs a function definition.

-
Your design needs work. Suppose the current page is 30 and the list of pages says "... 20 [30] 40 ..." as in your example. How do I get to page 29 or page 31? It doesn't look as if these page numbers will ever appear in the list.

The more usual design is to always show a small number of pages at the beginning and end, and a small number of pages adjacent to the current page. So that the list of pages would look more like "1 2 3 ... 28 29 [30] 31 32 ... 78 79 80".

-
The expression

int(float(count_all+(items_on_page-1))/float(items_on_page))


is unnecessarily complex. You can use Python's floor division operator (//) to achieve the same thing without converting to floats and back again:

(count_all + items_on_page - 1) // items_on_page


-
Your variables are poorly and unsystematically named. count_all, for example. All what? Or countpagesstr, which sounds like it might be a string, but is in fact a list. You use underscores in some cases (count_all) but not in others (countpages).

-
It is easiest conceptually to separate the two steps of deciding which page numbers to show and showing them in order with ellipses.

In the code below I build the set of the page numbers from the first three pages, the five pages around the current page, and the last three pages. I use Python's sets so that I can take this union without having to worry about duplicate page numbers.

def abbreviated_pages(n, page):
    """
    Return a string containing the list of numbers from 1 to `n`, with
    `page` indicated, and abbreviated with ellipses if too long.

    >>> abbreviated_pages(5, 3)
    '1 2 [3] 4 5'
    >>> abbreviated_pages(10, 10)
    '1 2 3 4 5 6 7 8 9 [10]'
    >>> abbreviated_pages(20, 1)
    '[1] 2 3 ... 18 19 20'
    >>> abbreviated_pages(80, 30)
    '1 2 3 ... 28 29 [30] 31 32 ... 78 79 80'
    """
    assert(0 < n)
    assert(0 < page <= n)

    # Build set of pages to display
    if n <= 10:
        pages = set(range(1, n + 1))
    else:
        pages = (set(range(1, 4))
                 | set(range(max(1, page - 2), min(page + 3, n + 1)))
                 | set(range(n - 2, n + 1)))

    # Display pages in order with ellipses
    def display():
        last_page = 0
        for p in sorted(pages):
            if p != last_page + 1: yield '...'
            yield ('[{0}]' if p == page else '{0}').format(p)
            last_page = p

    return ' '.join(display())

Code Snippets

int(float(count_all+(items_on_page-1))/float(items_on_page))
(count_all + items_on_page - 1) // items_on_page
def abbreviated_pages(n, page):
    """
    Return a string containing the list of numbers from 1 to `n`, with
    `page` indicated, and abbreviated with ellipses if too long.

    >>> abbreviated_pages(5, 3)
    '1 2 [3] 4 5'
    >>> abbreviated_pages(10, 10)
    '1 2 3 4 5 6 7 8 9 [10]'
    >>> abbreviated_pages(20, 1)
    '[1] 2 3 ... 18 19 20'
    >>> abbreviated_pages(80, 30)
    '1 2 3 ... 28 29 [30] 31 32 ... 78 79 80'
    """
    assert(0 < n)
    assert(0 < page <= n)

    # Build set of pages to display
    if n <= 10:
        pages = set(range(1, n + 1))
    else:
        pages = (set(range(1, 4))
                 | set(range(max(1, page - 2), min(page + 3, n + 1)))
                 | set(range(n - 2, n + 1)))

    # Display pages in order with ellipses
    def display():
        last_page = 0
        for p in sorted(pages):
            if p != last_page + 1: yield '...'
            yield ('[{0}]' if p == page else '{0}').format(p)
            last_page = p

    return ' '.join(display())

Context

StackExchange Code Review Q#15235, answer score: 8

Revisions (0)

No revisions yet.