Алгоритм / псевдокод для создания пейджинговых ссылок? - PullRequest
15 голосов
/ 04 сентября 2008

Может кто-нибудь предоставить код или псевдокод для генерации ссылок на страницы в StackOverflow?

Я продолжаю ломать голову, но не могу придумать достойного способа создания динамических ссылок, которые всегда показывают 2 страницы вокруг текущего, плюс первую и последнюю.

Пример: 1 ... 5 6 7 ... 593

Ответы [ 6 ]

43 голосов
/ 05 сентября 2008

Уже есть несколько других ответов, но я хотел бы показать вам подход, который я использовал, чтобы решить его: Во-первых, давайте посмотрим, как Stack Overflow обрабатывает обычные и крайние случаи. Каждая из моих страниц отображает 10 результатов, поэтому, чтобы узнать, что она делает для 1 страницы, найдите тег, который содержит менее 11 записей: удобство использования работает сегодня. Мы видим, что ничего не отображается, что имеет смысл.

Как насчет 2 страниц? Найдите тег, который содержит от 11 до 20 записей ( emacs работает сегодня). Мы видим: « 1 2 Next» или «Prev 1 2 », в зависимости от того, на какой странице мы находимся.

3 страницы? « 1 2 3 ... 3 Next», «Prev 1 2 3 Next» и «Prev 1 ... 2 3 ». Интересно, что мы видим, что само переполнение стека не очень хорошо справляется с этим краевым случаем: оно должно отображать « 1 2 ... 3 Next»

4 страницы? " 1 2 3 ... 4 Next", "Prev 1 2 3 ... 4 Next", "Prev 1 ... 2 3 4 Далее "и" Пред. 1 ... 3 4"

Наконец, давайте посмотрим на общий случай, N страниц: " 1 2 3 ... N Далее", "Предыдущая 1 2 3 ... N Следующая", " Предыдущая 1 ... 2 3 4 ... N Следующая "," Предыдущая 1 ... 3 4 5 ... N Следующая "и т. Д.

Давайте обобщим на основании того, что мы видели: Алгоритм, похоже, имеет следующие общие черты:

  • Если мы не на первой странице, отобразить ссылку на предыдущий
  • Всегда отображать номер первой страницы
  • Всегда отображать номер текущей страницы
  • Всегда отображать страницу до этой страницы и страницу после этой страницы.
  • Всегда отображать номер последней страницы
  • Если мы не на последней странице, отобразить ссылку на Далее

Давайте проигнорируем крайний край одной страницы и сделаем хорошую первую попытку алгоритма: (Как уже упоминалось, код для фактической распечатки ссылок будет более сложным. Представьте себе, где мы размещаем номер страницы, Пред или След в качестве вызова функции, которая вернет правильный URL.)

function printPageLinksFirstTry(num totalPages, num currentPage)
  if ( currentPage > 1 )
    print "Prev"
  print "1"
  print "..."
  print currentPage - 1
  print currentPage
  print currentPage + 1
  print "..."
  print totalPages
  if ( currentPage < totalPages )
    print "Next"
endFunction

Эта функция работает нормально, но она не учитывает, находимся ли мы на первой или последней странице. Глядя на приведенные выше примеры, мы хотим отобразить только ..., если текущая страница находится в двух или более раз.

function printPageLinksHandleCloseToEnds(num totalPages, num currentPage)
  if ( currentPage > 1 )
    print "Prev"
  print "1"
  if ( currentPage > 2 )
    print "..."
  if ( currentPage > 2 )
    print currentPage - 1
  print currentPage
  if ( currentPage < totalPages - 1 )
    print currentPage + 1
  if ( currentPage < totalPages - 1 )
    print "..."
  print totalPages
  if ( currentPage < totalPages )
    print "Next"
endFunction

Как видите, у нас есть некоторое дублирование. Мы можем пойти дальше и очистить это для удобства чтения:

function printPageLinksCleanedUp(num totalPages, num currentPage)
  if ( currentPage > 1 )
    print "Prev"
  print "1"
  if ( currentPage > 2 )
    print "..."
    print currentPage - 1
  print currentPage
  if ( currentPage < totalPages - 1 )
    print currentPage + 1
    print "..."
  print totalPages
  if ( currentPage < totalPages )
    print "Next"
endFunction

Осталось только две проблемы. Во-первых, мы неправильно распечатываем для одной страницы, а во-вторых, мы напечатаем «1» дважды, если мы на первой или последней странице. Давайте очистим их обоих за один раз:

function printPageLinksFinal(num totalPages, num currentPage)
  if ( totalPages == 1 )
    return

  if ( currentPage > 1 )
    print "Prev"

  print "1"

  if ( currentPage > 2 )
    print "..."
    print currentPage - 1

  if ( currentPage != 1 and currentPage != totalPages )
    print currentPage

  if ( currentPage < totalPages - 1 )
    print currentPage + 1
    print "..."

  print totalPages

  if ( currentPage < totalPages )
    print "Next"

endFunction

На самом деле я солгал: у нас осталась одна проблема. Если у вас есть как минимум 4 страницы и вы находитесь на первой или последней странице, вы получаете дополнительную страницу на своем дисплее. Вместо " 1 2 ... 10 Далее" вы получите " 1 2 3 ... 10 Далее". Чтобы точно соответствовать тому, что происходит в Stack Overflow, вам нужно проверить эту ситуацию:

function printPageLinksFinalReally(num totalPages, num currentPage)
  if ( totalPages == 1 )
    return

  if ( currentPage > 1 )
    print "Prev"

  print "1"

  if ( currentPage > 2 )
    print "..."
    if ( currentPage == totalPages and totalPages > 3 )
      print currentPage - 2
    print currentPage - 1

  if ( currentPage != 1 and currentPage != totalPages )
    print currentPage

  if ( currentPage < totalPages - 1 )
    print currentPage + 1
    if ( currentPage == 1 and totalPages > 3 )
      print currentPage + 2
    print "..."

  print totalPages

  if ( currentPage < totalPages )
    print "Next"

endFunction

Надеюсь, это поможет!

2 голосов
/ 04 сентября 2008

Элементы управления обычно отображают элементы управления для: P1, Pn, Pc (текущая страница), Pc + 1, Pc-1. Единственный раз, когда это изменение происходит на любом конце диапазона подкачки {Pc (Pn-3)}

  • Первый шаг - это определенное количество страниц:

numPages = ceiling(totalRecords / numPerPage)

  • Если у вас есть 4 или меньше, выпадать в этот момент, потому что, согласно вышеупомянутым правилам, подкачка всегда будет фиксированной (P1, P2, Pn-1, Pn), где один будет ПК

  • иначе у вас есть три "состояния"

а. (Pc 1, показать ссылку «предыдущая» перед P1.

б. (Pc> Pn - 2), поэтому показать Prev, P1, Pn - 2, Pn -1, Pn, показать следующую ссылку, если Pc

с. Показать Prev, P1, Pc -1, Pc, Pc +1, Pn, Next

Легко, как Pie в псевдокоде. Циклы могут быть немного неприятными при реализации, так как вам нужно выполнить некоторые итерации, чтобы сгенерировать ссылки.

Edit: Конечно Prev и Next идентичны Pc +/- 1

1 голос
/ 04 сентября 2008
public void PageLinks(int currentPage, int lastPage) {
    if (currentPage > 2) 
        Add('[1]', '...');
    for(int i=Math.Max(1, currentPage-1); i< Math.Min(currentPage+1, lastPage); i++)
        Add('[i]');
    if (currentPage < lastPage-1)
        Add('...', '[lastpage]');
}

lastPage рассчитывается как Math.Ceiling (totalRecords / RecordsPerPage).

Ммм. фактически, в случае, если текущая страница равна 3, она все еще показывает [1] ... [2] [3] [4] ... [xxx] я думаю, что эллипсы в этом случае излишни. Но вот как это работает.

Редактировать: предварительный просмотр правильно форматирует кодовый блок, почему он искажается? конечно, это просто псевдокод .... но все же ....

1 голос
/ 04 сентября 2008

Что ж, если вы знаете текущую страницу, довольно тривиально просто вычесть число на 1 и сложить его на 1, затем сравнить эти числа с границами и всегда отображать первую и последнюю страницу, а затем, если они не t, последовательно добавьте эллипсы.

Или вы спрашиваете о получении общего количества страниц и определении номера текущей страницы ...?

0 голосов
/ 23 августа 2018

Вот мой алгоритм, он работает очень хорошо:

    // Input
    total_items   // Number of rows, records etc. from db, file or whatever
    per_page      // num items per page
    page          // current page
    visible_pages // number of visible pages

    // Calculations
    lastPage = ceil(total_items / per_page);
    prevPage = page - 1 < 1 ? 0 : page - 1;
    nextPage = page + 1 > lastPage ? 0 : page + 1;
    halfpages = ceil(visible_pages / 2);
    startPage = page - halfpages < 1 ? 1 : page - halfpages;
    endPage = startPage + visible_pages - 1;
    if(endPage > lastPage) {
        startPage -= endPage - lastPage;
        startPage = startPage < 1 ? 1 : startPage;
        endPage = startPage + visible_pages > lastPage ? lastPage : startPage + visible_pages - 1;
    }

    // Output
    lastPage    // Total number of pages
    prevPage    // Previous page number (if 0 there is no prev page)
    nextPage    // Next page number (if 0 there is no next page)
    startPage   // First visible page
    endPage     // Last visible page

Так что вы можете сделать пейджер так:

    if prevPage
    [1] [prevPage] 
    endif

    [startPage] ... [endPage] 

    if nextPage
    [nextPage] [lastPage] 
    endif

или настройте что угодно.

0 голосов
/ 17 мая 2010

Это мой подход к созданию пейджинговой ссылки. Следующий Java-код - это просто псевдо.

package com.edde;

/**
 * @author Yang Shuai
 */
public class Pager {

    /**
     * This is a method used to display the paging links(pagination or sometimes called pager).
     * The totalPages are the total page you need to display. You can get this value using the
     * formula:
     * 
     *     total_pages = total_records / items_per_page
     * 
     * This methods is just a pseudo-code.
     * 
     * 
     * @param totalPages how many pages you need to display
     * @param currentPage you are in which page now
     */
    public static void printPageLinks(int totalPages, int currentPage) {

        // how many pages to display before and after the current page
        int x = 2;

        // if we just have one page, show nothing
        if (totalPages == 1) {
            return;
        }

        // if we are not at the first page, show the "Prev" button
        if (currentPage > 1) {
            System.out.print("Prev");
        }

        // always display the first page
        if (currentPage == 1) {
            System.out.print("    [1]");
        } else {
            System.out.print("    1");
        }

        // besides the first and last page, how many pages do we need to display?
        int how_many_times = 2 * x + 1;

        // we use the left and right to restrict the range that we need to display
        int left = Math.max(2, currentPage - 2 * x - 1);
        int right = Math.min(totalPages - 1, currentPage + 2 * x + 1);

        // the upper range restricted by left and right are more loosely than we need,
        // so we further restrict this range we need to display
        while (right - left > 2 * x) {
            if (currentPage - left < right - currentPage) {
                right--;
                right = right < currentPage ? currentPage : right;
            } else {
                left++;
                left = left > currentPage ? currentPage : left;
            }
        }

        // do we need display the left "..."
        if (left >= 3) {
            System.out.print("    ...");
        }

        // now display the middle pages, we display how_many_times pages from page left
        for (int i = 1, out = left; i <= how_many_times; i++, out++) {
            // there are some pages we need not to display
            if (out > right) {
                continue;
            }

            // display the actual page
            if (out == currentPage) {
                System.out.print("    [" + out + "]");
            } else {
                System.out.print("    " + out);
            }
        }

        // do we need the right "..."
        if (totalPages - right >= 2) {
            System.out.print("    ...");
        }

        // always display the last page
        if (currentPage == totalPages) {
            System.out.print("    [" + totalPages + "]");
        } else {
            System.out.print("    " + totalPages);
        }

        // if we are not at the last page, then display the "Next" button
        if (currentPage < totalPages) {
            System.out.print("    Next");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // printPageLinks(50, 3);
        help(500);
    }

    public static void test(int n) {
        for (int i = 1; i <= n; i++) {
            printPageLinks(n, i);
        }
        System.out.println("------------------------------");
    }

    public static void help(int n) {
        for (int i = 1; i <= n; i++) {
            test(i);
        }
    }

    public static void help(int from, int to) {
        for (int i = from; i <= to; i++) {
            test(i);
        }
    }

}
...