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

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

#Предварительная загрузка изображений. (49490 hits)
#Вычисление значения полинома. (64996 hits)
#Как посчитать одинаковые пары за 1 проход (самая быстрая версия!). (4644 hits)
#Подключение. (29349 hits)
#Вращение фигуры в плоскости. (42101 hits)
#Обработка шаблонных писем. (70721 hits)
#Динамическое формирование выпадающего списка. (54925 hits)
#Сравнение алгоритмов сортировки массива. (188652 hits)
#Случайный выбор нескольких несовпадающих значений из множества. (61897 hits)
#Наибольший общий делитель. (199294 hits)
#Переключатель в кириллицу. (34901 hits)
#Найти максимальную сумму в последовательности. (145796 hits)
#Сортировка Шелла, обший принцип. (149954 hits)
#Найти общие элементы в списках. (1866 hits)
#Двусторонняя карта. (36025 hits)
#"Липкие" окна. (34450 hits)
#Таймер. (42836 hits)
#Вычисление двойного интеграла с использованием MPI. (62746 hits)
#Программное создание ссылок. (102125 hits)
#Простая быстрая сортировка. (116497 hits)


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

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

Aвтор:
Дата:
Просмотров: 75609
реализации(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]