我在考虑使用C#或Java之类的语言时如何显示分页控件。
如果我有x个项目要以每页y个块的形式显示,那么需要多少个页面?
x
整除y
,则@IanNelson y/x + 1
会太高。
我在考虑使用C#或Java之类的语言时如何显示分页控件。
如果我有x个项目要以每页y个块的形式显示,那么需要多少个页面?
x
整除y
,则@IanNelson y/x + 1
会太高。
Answers:
找到了一个优雅的解决方案:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
pageCount = -((-records) // recordsPerPage)
。
在CPU级别上,转换为浮点数和返回浮点数似乎是浪费大量时间。
伊恩·尼尔森(Ian Nelson)的解决方案:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
可以简化为:
int pageCount = (records - 1) / recordsPerPage + 1;
AFAICS,它没有Brandon DuRette指出的溢出错误,并且由于它只使用一次,因此,如果它来自昂贵的函数来从配置文件中获取值,则不需要专门存储recordsPerPage。的东西。
也就是说,如果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;
-1 / 1 + 1 = 0
。尽管这不是一种普遍现象,但是如果允许用户调整页面大小,请务必牢记。因此,要么不允许用户的页面大小为1,要么对页面大小进行检查,或者同时检查两者(最好是避免出现意外行为)。
对于C#,解决方案是将值转换为双精度值(因为Math.Ceiling需要双精度值):
int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
在Java中,您应该对Math.ceil()执行相同的操作。
int
因为根据输入类型Math.Ceiling
返回a double
或decimal
。
这应该给您您想要的。您肯定希望每页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);
Ian提供的整数数学解决方案很好,但存在整数溢出错误。假设变量为all int
,则解决方案可以重写为使用long
数学运算并避免错误:
int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
如果records
为long
,则错误仍然存在。模数解决方案没有错误。
Nick Berardi的回答的变体避免了分支:
int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));
注意:(-r >> (Integer.SIZE - 1))
由的符号位组成r
,重复32次(由于>>
运算符的符号扩展。)如果r
为零或负,则结果为0,如果r
为正,则结果为-1 。因此q
,如果将其减去则具有加1的效果records % recordsPerPage > 0
。
对于记录== 0,rjmunro的解决方案给出1。正确的解决方案是0。也就是说,如果您知道记录> 0(并且我确定我们都假定recordsPerPage> 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
等),如果您愿意,可以随时添加。顺便说一下,对于那些担心方法调用开销的人来说,像这样的简单函数可能还是会被编译器内联,所以我不认为这是要关注的地方。干杯。
PS,您可能会发现也意识到这一点很有用(它会得到剩余的):
int remainder;
int result = Math.DivRem(dividend, divisor, out remainder);
DivideUp(4, -2)
返回0(应为-2)。它仅适用于从答案或函数接口不清楚的非负整数。
另一种选择是使用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;
您可以迭代其结果的通用方法可能引起您的兴趣:
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;
}
与以下解决方案相比,以下内容应做得更好,但以性能为代价(由于浮点计算为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;
}