ページングリンクを作成するためのアルゴリズム/疑似コード?

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

  •  09-06-2019
  •  | 
  •  

質問

StackOverflow 上のページング リンクがどのように生成されるかについて、誰かがコードまたは疑似コードを提供してもらえますか?

頭を悩ませ続けていますが、現在のページの前後 2 ページと最初と最後のページを常に表示するダイナミック リンクを構築する適切な方法が思いつきません。

例: 1 ... 5 6 7 ... 593

役に立ちましたか?

解決

すでに他にもいくつかの回答がありますが、それを解決するために私が取ったアプローチを示したいと思います。まず、スタック オーバーフローが通常のケースとエッジ ケースをどのように処理するかを確認してみましょう。私の各ページには 10 件の結果が表示されるため、1 ページで何が行われるかを確認するには、エントリが 11 未満のタグを見つけます。 使いやすさ 今日は働きます。何も表示されていないことがわかりますが、これは当然のことです。

2ページくらいでしょうか?11 ~ 20 個のエントリを持つタグを検索します (emacs 今日は動作します)。私たちは見る:」1 2 次へ」または「前へ 1 2"、どのページにいるかによって異なります。

3ページ?」1 2 3 ...3 次へ」、「前へ 1 2 3 次へ」、「前へ 1 ...2 3」。興味深いことに、スタック オーバーフロー自体はこのエッジ ケースをうまく処理していないことがわかります。「」と表示されるはずです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 ...N 次へ」、「前へ 1 ...2 3 4 ...N 次へ」、「前へ 1 ...3 4 5 ...Nネクスト』など。

これまで見てきたことに基づいて一般化してみましょう。このアルゴリズムには次のような共通の特徴があるようです。

  • 最初のページにいない場合は、「前へ」へのリンクを表示します
  • 最初のページ番号を常に表示する
  • 現在のページ番号を常に表示する
  • 常にこのページの前のページとこのページの後のページを表示します。
  • 最後のページ番号を常に表示する
  • 最後のページにいない場合は、「次へ」へのリンクを表示します

単一ページの特殊なケースを無視して、アルゴリズムの最初の試行をうまく行ってみましょう。(前述したように、リンクを実際に出力するコードはより複雑になります。正しい URL を返す関数呼び出しとして、ページ番号、Prev または Next を配置する各場所を想像してください)。

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

この関数は正常に動作しますが、最初のページに近いのか、最後のページに近いのかは考慮されません。上記の例を見ると、表示したいのは...現在のページが 2 ページ以上離れている場合。

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

残る問題は 2 つだけです。まず、1 ページが正しく印刷されません。次に、最初または最後のページの場合、「1」が 2 回印刷されます。これらの両方を一度にクリーンアップしましょう。

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

実は私は嘘をつきました:残りの問題が 1 つあります。少なくとも 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、Pc (現在のページ)、Pc+1、Pc-1。これが変化するのは、ページング範囲 {Pc < P3 または Pc > (Pn-3)} の両端のときのみです。

  • 最初のステップは、明らかにページ数を計算することです。

numPages = ceiling(totalRecords / numPerPage)

  • 4 以下の場合は、この時点でドロップアウトします。上記のルールにより、ページングは​​常に固定されるため (P1、P2、Pn-1、Pn)、実際には 1 つが Pc になります。

  • それ以外の場合は、3 つの「状態」があります

a.(Pc < P3) - したがって、P1、P2、P3、Pn、Next を表示します。Pc >1 の場合、P1 の前に「prev」リンクを表示します。

b.(Pc > Pn - 2) なので、Prev、P1、Pn - 2、Pn -1、Pn を表示し、Pc < Pn の場合は次のリンクを表示します。

c.前へ、P1、Pc -1、Pc、Pc +1、Pn、次へを表示

疑似コードで簡単に実行できます。リンクを生成するために反復処理を行う必要があるため、ループを実装すると少し厄介になる可能性があります。

編集:もちろん、Prev と Next は 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]');
}

lastPage は Math.Ceiling(totalRecords/RecordsPerPage) として計算されます。

うーん。実際、CurrentPageが3の場合、[1] ... [2] [3] [4] ... [xxx]その場合、[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