CodeLAB
на главную карта сайта обратная связь

Популярные задачи:

#Поверхностное клонирование. (27893 hits)
#Шейкер-сортировка. (71564 hits)
#Как посчитать одинаковые пары за 1 проход (самая быстрая версия!). (2358 hits)
#Относительный путь к файлу. (40033 hits)
#Бинарный поиск в массиве и его разновидности. (170008 hits)
#Овал, вписанный в прямоугольник. (38158 hits)
#Простая быстрая сортировка. (113241 hits)
#"C# и платформа .NET" Эндрю Троелсен (Andrew Troelsen, "C# and the .NET platform"), листинги, код, примеры из книги, исходники. (39109 hits)
#Предварительная загрузка изображений. (47447 hits)
#Сравнение алгоритмов быстрой сортировки. (74148 hits)
#Программное создание ссылок. (100107 hits)
#"The Java Programming Language" Ken Arnold, James Gosling, David Holmes листинги, код, примеры из книги, исходники. (61271 hits)
#Вычисление эксцесса и коэффициентов асимметрии заданной выборки. (46081 hits)
#Сглаживание кривой В-сплайном. (39033 hits)
#Использование компилируемых (prepared) запросов. (30905 hits)
#Арктангенс. (45751 hits)
#Подключение. (27603 hits)
#Динамическая очистка выпадающего списка (select) на javascript. (91196 hits)
#Преобразование целых чисел в битовый массив. (37888 hits)
#Счетчик времени с точностью до микросекунд. (129126 hits)


Главная >> Каталог задач >> Большие объемы данных >> Постраничный вывод

Постраничный вывод

Aвтор:
Дата:
Просмотров: 72972
реализации(php: 4шт...) +добавить

Введение

Очень распрастраненная задача, как в прикладном, так и в веб- программировании. Хотя в последнем случае - наверное все же ее приходится решать чаще...

Допустим имеется страница с таблицей(гридом и проч.), где нужно выводить огромное количество строк с однотипными данными. Например, этих однотипных элементов - несколько тысяч. Выводить все на одной странице(в одной форме) - довольно неразумно: и пользователю будет трудно воспринимать все это и технически рендеринг/вырисовывание всех этих строк - может занять довольно продолжительное время в зависимости от скорости компьютера пользователя:

data1 data2 data3 ............. dataN
data21 data22 data23 ............. data2N
data31 data32 data33 ............. data3N
..
..
..
..... здесь еще сотни таких строк..
..
...
dataM1 dataM2 dataM3 ............. dataMN

Логичное и самое правильное решение - разбить эту таблицу на несколько страниц, а внизу поставить ссылки(кнопки) переключения на другие страницы.

Формализация

Формализуем задачу.

На входе имеем:

  1. Суммарное количество доступных для просмотра объектов(N)
  2. Максимальное число объектов, которое может отображаться пользователю на одной странице(perPage)
  3. Id страницы, которую нужно отобразить на данный момент. Обычно это либо просто порядковый номер (currPageNum) данной страницы, начиная с 1-ой, либо смещение(currOffset), показывающее сколько объектов нужно пропустить.

На выходе нужно получить список страниц рассмотрев различные варианты, например:

  1. Простой список номеров всех страниц с выделение номера(7) текущей страницы:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  2. Вариант №1 +ссылки "предыдущая" и "следующая" страницы:
    предыдущая(6) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  следующая(8),
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  следующая(2),
    предыдущая(14) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  3. Расширенный список, отображающий номера страниц, только близлежащие с номером текущей просматриваемой страницы(в пределах некоторого настраиваемого диапазона конечно) +ссылки "предыдущая" и "следующая" страницы:
    предыдущая(6) ... 4 5 6 7 8 9 10 ... следующая(8),
    предыдущая(2) 1 2 3 4 5 6 ... следующая(4),
    предыдущая(13) ... 11 12 13 14 15  следующая(15)
    Поскольку страниц может быть тысячи, поэтому их перечисление будет занимать много места и вообще будет неудобным. Как видно, "настраиваемый диапазон" здесь - это 3 страницы до и 3 после. Конечно, с возможностью менять это число 3 как заблагорассудится.
  4. Вариант 3 +отображение номера первой и последней страницы:
    предыдущая(6) 1 ... 5 6 7 8 9 ... 15  следующая(8)

Рассмотрим каждый из вариантов в отдельности. При этом в качестве id страницы будем использовать смещение как наиболее простой и универсальный вариант.

Простой список

Самый простой соответсвенно алгоритм:

 псевдокод: Простой список  ссылка
  1. // Номер страницы(для пользователя)
  2. currNum = 0
  3. for i = 0; i < N; i += perPage
  4. currNum++
  5. if i == currOffset
  6. print currNum
  7. else
  8. // Выводим номер как ссылку на след.
  9. // страницу, определяя ее через новое
  10. // смещение, которое будет == i
  11. print currNum as <ref> where [offset=i]

 

Простой список +предыдущая и следущая страницы

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

 псевдокод: простой список +предыдущая и следующая страницы  ссылка
  1. // Рассчитываем смещение предыдущей страницы
  2. prevOffset = -1;
  3. if currOffset - perPage >= 0
  4. prevOffset = currOffset - perPage;
  5.  
  6. // Рассчитываем смещение для следующей страницы
  7. nextOffset = 0;
  8. if currOffset + perPage < N
  9. nextOffset = currOffset + perPage;
  10.  
  11. // Выводим ссылку(кнопку) на предыдущую страницу
  12. if prevOffset >= 0
  13. print "Previous Page" as <ref> where [offset=prevOffset]
  14.  
  15. // Номер страницы(для пользователя)
  16. currNum = 0
  17.  
  18. for i = 0; i < N; i += perPage
  19. currNum++
  20. if i == offset
  21. print currNum
  22. else
  23. // Выводим номер как ссылку на след.
  24. // страницу, определяя ее через новое
  25. // смещение, которое будет == i
  26. print currNum as <ref> where [offset=i]
  27.  
  28. // Выводим ссылку(кнопку) на следующую страницу
  29. if nextOffset > 0
  30. print "Next Page" as <ref> where [offset=nextOffset]

Обратите внимание на строчку 12: prevOffset вполне возможно может быть нулевым, что будет означать ссылку на первую страницу и будет иметь место при текущей странице - вторая страница.

Расширенный список

Здесь начинается самое интересное, поскольку в этом случае возникает уже довольно много вариантов "сокрытия" ненужных номеров страниц и регулировки этого диапазона сокрытия. Один из них может может выглядеть как:

 псевдокод: Расширенный список  ссылка
  1. // Количество соседних номеров страниц с каждой стороны,
  2. // отображающихся рядом с текущей страницей
  3. // Т.н. упомянутая "регулировка диапазона сокрытия"
  4. xwidth = 3;
  5.  
  6. // Рассчитываем смещение предыдущей страницы
  7. prevOffset = -1;
  8. if currOffset - perPage >= 0
  9. prevOffset = currOffset - perPage;
  10.  
  11. // Рассчитываем смещение для следующей страницы
  12. nextOffset = 0;
  13. if currOffset + perPage < N
  14. nextOffset = currOffset + perPage;
  15.  
  16. // Выводим ссылку(кнопку) на предыдущую страницу
  17. if prevOffset >= 0
  18. print "Previous Page" as <ref> where [offset=prevOffset]
  19.  
  20. // Номер страницы(для пользователя)
  21. currNum = 0
  22.  
  23.  
  24. // Флаги вывода левого и правого многоточия
  25. $leftBlankOut = $rightBlankOut = false;
  26.  
  27. for i = 0; i < N; i += perPage
  28. currNum++
  29.  
  30. // Манипулируем выводом левого многоточия
  31. if (i <= currOffset - xwidth * perPage - perPage)
  32. if (!leftBlankOut) print '...' // Вывод левого многоточия
  33. leftBlankOut = true
  34. continue
  35.  
  36. // Манипулируем выводом правого многоточия
  37. if (i >= currOffset + xwidth * perPage + perPage)
  38. if (!rightBlankOut) print '...' // Вывод правого многоточия
  39. rightBlankOut = true
  40. continue
  41.  
  42. if i == offset
  43. print currNum
  44. else
  45. // Выводим номер как ссылку на след.
  46. // страницу, определяя ее через новое
  47. // смещение, которое будет == i
  48. print currNum as <ref> where [offset=i]
  49.  
  50. // Выводим ссылку(кнопку) на следующую страницу
  51. if nextOffset > 0
  52. print "Next Page" as <ref> where [offset=nextOffset]


Как видим данный алгоритм позволяет легко настраивать дипазаон выводимых номеров вокруг текущего простым изменением переменной xwidth.

Расширеный список + первая и последняя страницы

Для этого нам потребуется внести лишь небольшие изменения в алгоритм предыдущего варианта:

 псевдокод: Расширенный список +первая и последняя страницы  ссылка
  1. // Количество соседних номеров страниц с каждой стороны,
  2. // отображающихся рядом с текущей страницей
  3. // Т.н. упомянутая "регулировка диапазона сокрытия"
  4. xwidth = 3;
  5.  
  6. // Рассчитываем смещение предыдущей страницы
  7. prevOffset = -1;
  8. if currOffset - perPage >= 0
  9. prevOffset = currOffset - perPage;
  10.  
  11. // Рассчитываем смещение для следующей страницы
  12. nextOffset = 0;
  13. if currOffset + perPage < N
  14. nextOffset = currOffset + perPage;
  15.  
  16. // Выводим ссылку(кнопку) на предыдущую страницу
  17. if prevOffset >= 0
  18. print "Previous Page" as <ref> where [offset=prevOffset]
  19.  
  20. // Номер страницы(для пользователя)
  21. currNum = 0
  22.  
  23.  
  24. // Флаги вывода левого и правого многоточия
  25. $leftBlankOut = $rightBlankOut = false;
  26.  
  27. for i = 0; i < N; i += perPage
  28. currNum++
  29.  
  30. // Манипулируем выводом левого многоточия
  31. if (i > 0) && (i <= currOffset - xwidth * perPage - perPage)
  32. if (!leftBlankOut) print '...' // Вывод левого многоточия
  33. leftBlankOut = true
  34. continue
  35.  
  36. // Манипулируем выводом правого многоточия
  37. if (i < N - perPage) && (i >= currOffset + xwidth * perPage + perPage)
  38. if (!rightBlankOut) print '...' // Вывод правого многоточия
  39. rightBlankOut = true
  40. continue
  41.  
  42. if i == offset
  43. print currNum
  44. else
  45. // Выводим номер как ссылку на след.
  46. // страницу, определяя ее через новое
  47. // смещение, которое будет == i
  48. print currNum as <ref> where [offset=i]
  49.  
  50. // Выводим ссылку(кнопку) на следующую страницу
  51. if nextOffset > 0
  52. print "Next Page" as <ref> where [offset=nextOffset]


Как видно по сравнению с предующим вариантом добавились лишь пара условий в строки 31 и 37.

Реализации:

php(4)   +добавить

1) Простой список на php, code #84[автор:this]
2) Простой список +предыдущая/следущая страницы на php, code #85[автор:this]
3) Расширенный список на php, code #86[автор:this]
4) Расширенный список + первая/последняя страницы на php, code #87[автор:this]