Я имею в виду, в частности, как отображать элементы управления разбиением на страницы, при использовании языка, такого как С# или Java.
Если у меня есть x элементов, которые я хочу отобразить в кусках y на странице, сколько страниц потребуется?
Я имею в виду, в частности, как отображать элементы управления разбиением на страницы, при использовании языка, такого как С# или Java.
Если у меня есть x элементов, которые я хочу отобразить в кусках y на странице, сколько страниц потребуется?
Нашел элегантное решение:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Преобразование в плавающие точки и обратно кажется огромной тратой времени на уровне процессора.
Решение Яна Нельсона:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Можно упростить:
int pageCount = (records - 1) / recordsPerPage + 1;
AFAICS, у этого нет ошибки переполнения, о которой указал Brandon DuRette, и поскольку она использует ее только один раз, вам не нужно специально хранить файл recordPerPage, если он исходит из дорогостоящей функции для извлечения значения из конфигурационный файл или что-то в этом роде.
т.е. это может быть неэффективным, если config.fetch_value использует поиск базы данных или что-то еще:
int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');
Это создает переменную, которая вам действительно не нужна, что, вероятно, имеет (незначительные) последствия для памяти и слишком много печатает:
int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Это все одна строка и только один раз извлекает данные:
int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
Это должно дать вам то, что вы хотите. Вы определенно хотите, чтобы x элементов делились на y элементов на страницу, проблема в том, что возникают неравномерные числа, поэтому, если есть частичная страница, мы также хотим добавить одну страницу.
int x = number_of_items;
int y = items_per_page;
// with out library
int pages = x/y + (x % y > 0 ? 1 : 0)
// with library
int pages = (int)Math.Ceiling((double)x / (double)y);
Для С# решение заключается в том, чтобы преобразовать значения в double (поскольку Math.Ceiling берет двойной):
int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
В java вы должны сделать то же самое с Math.ceil().
Целочисленное математическое решение, предоставляемое Ian, является приятным, но оно страдает от ошибки переполнения целого числа. Предполагая, что все переменные int
, решение можно переписать, чтобы использовать математику long
и избежать ошибки:
int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
Если records
является long
, ошибка остается. Решение модуля не имеет ошибки.
Вариант ответа Ник Берарди, который позволяет избежать ветки:
int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));
Примечание: (-r >> (Integer.SIZE - 1))
состоит из знакового бита r
, повторяющегося 32 раза (благодаря расширению знака оператора >>
.) Это оценивается как 0, если r
равно нулю или отрицательно, -1, если r
является положительным. Таким образом, вычитание из q
имеет эффект добавления 1, если records % recordsPerPage > 0
.
Для записей == 0 решение rjmunro дает 1. Правильное решение равно 0. При этом, если вы знаете, что записи > 0 (и я уверен, что все принятые записиPerPage > 0), то решение rjmunro дает правильные результаты и не имеют проблем с переполнением.
int pageCount = 0;
if (records > 0)
{
pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required
Все целочисленные математические решения будут эффективнее любого из решений с плавающей запятой.
Необходим метод расширения:
public static int DivideUp(this int dividend, int divisor)
{
return (dividend + (divisor - 1)) / divisor;
}
Здесь нет проверок (переполнение, DivideByZero
и т.д.), не стесняйтесь добавлять, если хотите. Кстати, для тех, кто беспокоится о накладных расходах метода, простые функции, подобные этому, могут быть встроены компилятором в любом случае, поэтому я не думаю, что там, где это нужно. Приветствия.
P.S. вам может быть полезно знать об этом (он получает остаток):
int remainder;
int result = Math.DivRem(dividend, divisor, out remainder);
Другой вариант - использовать функцию mod() (или '%'). Если есть ненулевой остаток, то увеличивайте целочисленный результат деления.
Выполняю следующее: обрабатывает любые переполнения:
var totalPages = totalResults.IsDivisble(recordsperpage) ? totalResults/(recordsperpage) : totalResults/(recordsperpage) + 1;
И используйте это расширение, если есть 0 результатов:
public static bool IsDivisble(this int x, int n)
{
return (x%n) == 0;
}
Кроме того, для текущего номера страницы (не было задано, но может быть полезно):
var currentPage = (int) Math.Ceiling(recordsperpage/(double) recordsperpage) + 1;
Альтернатива для удаления ветвления при тестировании на ноль:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage * (records != 0);
Не уверен, что это будет работать на С#, нужно делать в C/С++.
Может быть интересен общий метод, результат которого вы можете перебрать:
public static Object[][] chunk(Object[] src, int chunkSize) {
int overflow = src.length%chunkSize;
int numChunks = (src.length/chunkSize) + (overflow>0?1:0);
Object[][] dest = new Object[numChunks][];
for (int i=0; i<numChunks; i++) {
dest[i] = new Object[ (i<numChunks-1 || overflow==0) ? chunkSize : overflow ];
System.arraycopy(src, i*chunkSize, dest[i], 0, dest[i].length);
}
return dest;
}
У меня была аналогичная потребность, когда мне нужно было преобразовать минуты в часы и минуты. Я использовал:
int hrs = 0; int mins = 0;
float tm = totalmins;
if ( tm > 60 ) ( hrs = (int) (tm / 60);
mins = (int) (tm - (hrs * 60));
System.out.println("Total time in Hours & Minutes = " + hrs + ":" + mins);
Следующее должно делать округление лучше, чем вышеупомянутые решения, но за счет производительности (из-за вычисления с плавающей запятой 0.5 * rctDenominator):
uint64_t integerDivide( const uint64_t& rctNumerator, const uint64_t& rctDenominator )
{
// Ensure .5 upwards is rounded up (otherwise integer division just truncates - ie gives no remainder)
return (rctDenominator == 0) ? 0 : (rctNumerator + (int)(0.5*rctDenominator)) / rctDenominator;
}
Вы хотите сделать деление с плавающей запятой, а затем использовать функцию потолка, чтобы округлить значение до следующего целого числа.