Алгоритм / псевдокод для создания ссылок подкачки?

StackOverflow https://stackoverflow.com/questions/44542

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

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

Как насчет 2 страниц?Найдите тег, содержащий от 11 до 20 записей (emacs работает сегодня).Мы видим:"1 2 Следующий" или "Предыдущий 1 2", в зависимости от того, на какой странице мы находимся.

3 страницы?"1 2 3 ...3 Следующий", "Предыдущий 1 2 3 Далее", и "Предыдущая статья 1 ...2 3".Интересно, что мы можем видеть, что само по себе Stack Overflow не очень хорошо справляется с этим граничным случаем:он должен отображать "1 2 ...3 Следующий"

4 страницы?"1 2 3 ...4 Далее", "Предыдущая статья 1 2 3 ...4 Далее", "Предыдущая статья 1 ...2 3 4 Далее" и "Предыдущая статья 1 ...3 4"

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

Давайте сделаем обобщение, основываясь на том, что мы видели:Похоже, у алгоритма есть эти общие черты:

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

Давайте проигнорируем граничный случай одной страницы и сделаем хорошую первую попытку использования алгоритма:(Как уже упоминалось, код для фактической печати ссылок был бы более сложным.Представьте, что в каждом месте мы размещаем номер страницы, предыдущую или Следующую в виде вызова функции, которая вернет правильный 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 Следующий".Чтобы точно соответствовать тому, что происходит при переполнении стека, вам нужно будет проверить эту ситуацию:

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

Я надеюсь, что это поможет!

Другие советы

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

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

numPages = ceiling(totalRecords / numPerPage)

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

  • в противном случае у вас есть три "состояния".

a.(ПК < P3) - итак, покажите P1, P2, P3, Pn, Затем, если Pc>1, покажите предыдущую ссылку перед P1.

b.(Pc> Pn - 2), поэтому покажите Предыдущие, P1, Pn - 2, Pn -1, Pn, покажите Следующую ссылку, если Pc < Pn

c.Показать предыдущее, P1, Pc -1, Pc, Pc +1, Pn, Далее

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

Редактировать:Конечно, предыдущие и Следующие идентичны Pc +/- 1

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

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

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]');
}

Последняя страница рассчитывается математически.Потолок (TotalRecords /recordsPerPage).

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

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

Это мой подход к созданию ссылки для подкачки.Следующее 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);
        }
    }

}

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

    // 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

или настройте все, что вам нравится.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top