Algorytm / pseudo-kod do tworzenia linków przywoławczych?
Czy someome może dostarczyć kod lub pseudo-kod do generowania linków stronicowania w StackOverflow?
Ciągle rozpracowuję swój mózg, ale nie mogę wymyślić przyzwoitego sposobu na zbudowanie dynamicznych linków, które zawsze pokazują 2 strony wokół bieżącego, plus pierwszą i ostatnią.
Przykład: 1 ... 5 6 7 ... 593
6 answers
Jest już kilka innych odpowiedzi, ale chciałbym pokazać, jakie podejście zastosowałem, aby je rozwiązać: Po pierwsze, sprawdźmy, jak Stack Overflow obsługuje zwykłe przypadki i przypadki krawędzi. Każda z moich stron wyświetla 10 wyników, więc aby dowiedzieć się, co robi dla 1 strony, znajdź tag, który ma mniej niż 11 wpisów: usability działa dzisiaj. Widzimy, że nic nie jest wyświetlane, co ma sens.
Może 2 strony? Znajdź tag, który zawiera od 11 do 20 wpisów (Emacs działa dzisiaj). Widzimy: "1 2 Next " lub " Prev 1 2", zależy, na której stronie jesteśmy.
3 strony? "1 2 3 ... 3 Next", "Prev 1 2 3 Next", oraz " Prev 1 ... 2 3". Co ciekawe, widzimy, że sam Stack Overflow nie radzi sobie z tym przypadkiem krawędzi: powinien wyświetlać "1 2 ... 3 Następna "
4 strony? "1 2 3 ... 4 Next", " Prev 1 2 3 ... 4 Next", " Prev 1 ... 2 3 4 Next " i " Prev 1 ... 3 4"
Wreszcie spójrzmy na ogólny przypadek, N stron: "1 2 3 ... N Next", " Prev 1 2 3 ... N Next", " Prev 1 ... 2 3 4 ... N Next", " Prev 1 ... 3 4 5 ... N Next", itp.
Uogólnijmy na podstawie tego, co widzieliśmy: Algorytm wydaje się mieć te cechy wspólne:
- Jeśli nie jesteśmy na pierwszej stronie, wyświetl link do Prev
- zawsze wyświetl numer pierwszej strony
- Zawsze wyświetlaj aktualny numer strony
- zawsze wyświetla stronę przed tą stroną i stronę po tej stronie.
- zawsze wyświetl numer ostatniej strony
- Jeśli nie jesteśmy na ostatniej stronie, wyświetl link do następnej
Zignorujmy Rozmiar Krawędzi pojedynczej strony i podejmijmy dobrą pierwszą próbę algorytmu: (jak już wspomniano, kod do wydrukowania linków byłby bardziej skomplikowany. Wyobraź sobie każde miejsce umieszczamy numer strony, Prev lub Next jako wywołanie funkcji zwróci poprawny adres 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
Ta funkcja Działa ok, ale nie bierze pod uwagę, czy jesteśmy w pobliżu pierwszej czy ostatniej strony. Patrząc na powyższe przykłady, chcemy tylko wyświetlić ... jeśli bieżąca strona znajduje się dwa lub więcej.
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
Jak widzisz, mamy tu pewne dublowanie. Możemy śmiało to wyczyścić dla czytelności:
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
Zostały tylko dwa problemy. Po pierwsze, nie drukujemy poprawnie jednej strony, a po drugie, będziemy wydrukuj" 1 " dwa razy, jeśli jesteśmy na pierwszej lub ostatniej stronie. Oczyśćmy je za jednym razem:
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
Właściwie, skłamałem: mamy jeszcze jeden problem. Jeśli masz co najmniej 4 strony i jesteś na pierwszej lub ostatniej stronie, otrzymasz dodatkową stronę na ekranie. Zamiast "1 2 ... 10 Następna""1 2 3 ... 10 Następna" Aby dokładnie dopasować to, co dzieje się w Stack Overflow, musisz sprawdzić tę sytuację:
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
Mam nadzieję, że to pomoże!Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:53
Kontrolki zazwyczaj pokazują kontrolki dla: P1, Pn, Pc( bieżąca strona), Pc+1, Pc-1. Zmiana ta następuje tylko na obu końcach zakresu stronicowania {Pc (Pn-3)}
- pierwszym krokiem jest oczywiście obliczenie liczby stron:
numPages = ceiling(totalRecords / numPerPage)
-
Jeśli masz 4 lub mniej, drop out w tym momencie, ponieważ, zgodnie z powyższymi zasadami, stronicowanie zawsze będzie stałe (P1, P2, Pn-1, Pn), gdzie jeden będzie acutally Pc
-
Else, masz trzy "stany"
A. (Pc 1, Pokaż link 'prev' przed P1.
B. (Pc > Pn - 2), więc pokaż Prev, P1, Pn-2, Pn -1, PN, Pokaż następny link, jeśli Pc
C. Pokaż Prev, P1, Pc -1, Pc, Pc +1, PN, Next
Proste jak Pie w pseudo kodzie. Pętle mogą być nieco nieprzyjemne po zaimplementowaniu, ponieważ musisz wykonać kilka iteracji, aby wygenerować linki.
Edytuj: Oczywiście Prev i Next są identyczne jak Pc +/- 1
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 20:15:45
Cóż, jeśli znasz bieżącą stronę, to dość trywialne jest po prostu odjąć liczbę przez 1 i dodać ją przez 1, a następnie sprawdzić te liczby względem granic i wyświetlać zawsze pierwszą i ostatnią stronę, a następnie, jeśli nie są w kolejności, dodaj elipsy.
A może pytasz o uzyskanie całkowitej liczby stron i określenie bieżącego numeru strony...?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 19:26:41
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 jest obliczany jako matematyka.Sufit(totalRecords/Recordspepage).
Hmmm. w rzeczywistości, w przypadku, gdy currentpage jest 3, nadal pokazuje [1]...[2][3][4]...[xxx] myślę, że elipsy są w tym przypadku zbędne. Ale tak to działa.Edit: podgląd formatuje kod poprawnie, dlaczego jest zniekształcony? jasne, to tylko pseudokod.... ale jednak....
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-04 20:02:54
Oto moje podejście do tworzenia łącza przywoławczego. Następujące kod java to tylko pseudo.
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);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 07:30:03
Oto mój algorytm. Działa naprawdę ładnie:
// 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
Więc możesz zrobić pager taki:
if prevPage
[1] [prevPage]
endif
[startPage] ... [endPage]
if nextPage
[nextPage] [lastPage]
endif
Albo dostosuj, co chcesz.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-19 14:17:52