我特别在考虑使用诸如C#或Java之类的语言时如何显示分页控件。页面是否需要?

评论

我想念什么吗? y / x +1效果很好(前提是您知道/运算符总是四舍五入)。

@rikkit-如果y和x相等,则y / x +1太高。

对于刚刚发现此问题的任何人,此重复问题的答案除了提供了明确的解释外,还避免了不必要的转换为双精度,并避免了溢出问题。
@IanNelson更一般地说,如果x可被y整除,则y / x +1会太高。

@ ZX9不,它不能避免溢出问题。它与Ian Nelson在此处发布的解决方案完全相同。

#1 楼

找到了一个优雅的解决方案:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;


资料来源:罗兰·巴克豪斯(Roland Backhouse),Number Conversion,2001年

评论


-1,因为Brandon DuRette指出了溢出错误

– Finnw
2011年5月4日9:21

Obvious先生说:请记住确保recordsPerPage不为零

–亚当·根特(Adam Gent)
11年5月19日在11:41

干得好,我不敢相信C#没有整数上限。

– gosukiwi
2012年8月29日在18:32

是的,在尝试几种更为复杂的方法之后,我在2017年中期遇到了这个好答案。

– Mifo
17年7月29日在23:41

对于具有适当Euclidian除法运算符的语言(例如Python),甚至更简单的方法是pageCount =-((-records)// recordsPerPage)。

–超级猫
18年7月4日在16:45

#2 楼

在CPU级别上转换为浮点和返回似乎是浪费时间。

Ian Nelson的解决方案:到:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;


AFAICS,它没有布兰登·杜莱特(Brandon DuRette)指出的溢出错误,因为它只使用一次,所以不需要存储特别是recordsPerPage,如果它是从昂贵的函数中获取的,该函数是从配置文件或其他内容中获取值的。

即如果config.fetch_value使用数据库查找或其他方法,则这可能是低效率的:涉及内存,并且键入过多:

int pageCount = (records - 1) / recordsPerPage + 1;


这是全部一行,并且仅提取一次数据:

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');


评论


+1,零记录仍然返回1 pageCount的问题实际上很方便,因为我仍然想要1页,显示占位符/伪造行“没有符合条件的记录”,有助于避免任何情况下的“ 0页数”问题您使用的分页控件。

–提莫西·沃尔特斯(Timothy Walters)
2011-3-17的2:38

请注意,对于零个记录,两个解决方案不会返回相同的pageCount。此简化版本将为零记录返回1 pageCount,而Roland Backhouse版本将返回0 pageCount。如果这是您想要的,就很好,但是当由C#/ Java stylee整数除法执行时,两个方程式并不相等。

–伊恩·尼尔森(Ian Nelson)
2011年9月6日7:48在

从Nelson解决方案更改为简化后,人们进行细微编辑以使人们扫描它并丢失胸部(就像我第一次这样做!),带括号的简化为... int pageCount =((records-1)/ recordsPerPage) + 1;

–戴夫·海伍德
2014年5月2日在8:41

您应该在简化版本中添加括号,以使其不依赖于特定的操作顺序。即(((records-1)/ recordsPerPage)+ 1。

–马丁
16年2月5日在17:57

@Ian,此答案不会始终返回1。如果您的recordsPerPage为“ 1”并且有0条记录,则可以返回0:-1 / 1 + 1 =0。虽然这不是一个超常见的情况,但保持请注意,如果您允许用户调整页面大小。因此,要么不允许用户的页面大小为1,要么对页面大小进行检查,或者同时检查两者(最好是避免出现意外行为)。

–迈克尔
18年1月9日在23:39



#3 楼

对于C#,解决方案是将值转换为双精度值(因为Math.Ceiling取双精度值):

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);


在Java中,您应该对Math.ceil进行相同操作()。

评论


当op明确要求C#时,为什么这个答案如此之低!

–felickz
2012年10月1日20:46



您还需要将输出强制转换为int,因为Math.Ceiling根据输入类型返回双精度或十进制。

– DanM7
2012-10-17 21:28



因为它效率极低

– Zar Shardan
13年4月4日在13:05

它可能效率低下,但非常容易理解。给定计算页数通常每个请求执行一次,任何性能损失都是无法衡量的。

– Jared Kells
2015年4月7日在6:21

它几乎比“(除数+(除数-1))/除数”更具可读性;还慢,需要数学库。

–卷
17年4月24日在6:47

#4 楼

这应该给您您想要的。您肯定希望每页用x个项目除以y个项目,问题是出现不均匀数字时,因此,如果有部分页面,我们也要添加一页。

评论


x / y + !!(x%y)避免了类C语言的分支。几率很好,但是您的编译器还是会这样做。

– Rhys Ulerich
2010-1-26的15:57

+1不会像上面的答案那样溢出...尽管仅将整数转换为Math.ceiling的double,然后再次返回,这对性能敏感的代码却不是一个好主意。

–齿轮
2015年2月25日,下午1:54

@RhysUlerich在c#中不起作用(无法将int直接转换为bool)。我认为rjmunro的解决方案是避免分支的唯一方法。

–smead
16年4月9日在1:05

#5 楼

Ian提供的整数数学解决方案很好,但存在整数溢出错误。假设变量全部为int,则可以重写该解决方案以使用long数学运算并避免错误:模数解决方案没有bug。

评论


我认为您不会在提出的方案中实际遇到此错误。 2 ^ 31条记录需要分页。

– rjmunro
09年2月5日,0:18

@rjmunro,此处为真实示例

– Finnw
2011年5月4日,9:20

@finnw:AFAICS,该页面上没有一个实际的示例,只是有关其他人在理论上发现该错误的报告。

– rjmunro
11年11月29日在11:44

是的,我一直在指出该错误。可以永久存在许多错误,而不会引起任何问题。在有人报告它之前,JDK的binarySearch实现中存在相同形式的错误已有九年之久(googleresearch.blogspot.com/2006/06/…)。我想问题是,无论您遇到这种错误的可能性有多大,为什么不先解决它?

–布兰登·杜莱特
2011年11月29日17:59

另外,应该注意的是,重要的不仅仅是页面的元素数量,还有页面大小。因此,如果您正在构建一个库,并且有人选择不通过传递2 ^ 31-1(Integer.MAX_VALUE)作为页面大小来进行分页,则会触发该错误。

–布兰登·杜莱特
11年11月29日在18:03

#6 楼

尼克·贝拉迪(Nick Berardi)回答的一种避免分支的变体:如果(-r >> (Integer.SIZE - 1))为零或负,则求值为0;如果r为正,则求值为-1。因此,如果>>r中减去则具有加1的效果。

#7 楼

对于记录== 0,rjmunro的解决方案给出1。正确的解决方案是0。也就是说,如果您知道记录> 0(并且我确定我们都假定recordsPerPage> 0),那么rjmunro的解决方案就会给出正确的结果,并且不会有任何溢出问题。

int pageCount = 0;
if (records > 0)
{
    pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required


所有整数数学解决方案都将比任何浮点解决方案更有效。

评论


此方法不太可能成为性能瓶颈。如果是这样,您还应该考虑分支机构的成本。

– Finnw
2011年5月4日13:14

#8 楼

需要扩展方法:

    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);


评论


这是不正确的。例如:DivideUp(4,-2)返回0(应为-2)。它仅适用于从答案或函数界面不清楚的非负整数。

– Thash
17年4月25日在21:31

推销,为什么不做一些有用的操作,例如添加一些额外的检查,然后在数字为负数的情况下,而不是投票否决我的答案,并错误地做出笼统的声明:“这是不正确的”,而实际上这只是边缘案件。我已经明确表示您应该首先进行其他检查:“此处没有检查(溢出,DivideByZero等),您可以根据需要随意添加。”

–尼古拉斯·彼得森(Nicholas Petersen)
17-4-25在23:18



该问题提到“我特别在考虑如何显示分页控件”,因此无论如何负数都将超出范围。同样,做一些有用的事情,如果需要的话,建议增加检查,这是团队合作精神。

–尼古拉斯·彼得森(Nicholas Petersen)
17-4-25在23:22

我不是无礼的意思,对不起,如果您这么认为的话。问题是“如何对整数除法的结果取整”。作者提到了分页,但是其他人可能有不同的需求。我认为,如果您的函数以某种方式反映出它不适用于负整数会更好,因为从接口中看不出来(例如,不同的名称或参数类型)。要使用负整数,例如,您可以取除数和除数的绝对值,然后将结果乘以其符号。

– Thash
17年4月26日在7:51



#9 楼

另一种选择是使用mod()函数(或'%')。如果存在非零的余数,则将除法的整数结果递增。

#10 楼

我执行以下操作,处理所有溢出: br />此外,对于当前页码(未询问,但可能有用):

var totalPages = totalResults.IsDivisble(recordsperpage) ? totalResults/(recordsperpage) : totalResults/(recordsperpage) + 1;


#11 楼

如何在C#中累积整数除法的结果
我很想知道在C#中这样做的最好方法是什么,因为我需要循环执行近十万次。其他人使用Math发布的解决方案在答案中排名很高,但是在测试中我发现它们很慢。 Jarod Elliott提出了一种更好的策略来检查mod是否产生任何东西。这是使用Math的代码:

#12 楼

在零测试中删除分支的替代方法:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage * (records != 0);


不确定是否可以在C#中工作,应该在C / C ++中工作。

#13 楼

可以迭代其结果的通用方法可能很有趣:

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;
}


评论


番石榴也有类似的方法(Lists.partition(List,int)),具有讽刺意味的是,生成的List的size()方法(截至r09)遭受了Brandon DuRette的回答中提到的溢出错误。

– Finnw
2011年5月4日13:21



#14 楼

我有类似的需要,我需要将分钟转换为小时和分钟。我使用的是:

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);


#15 楼

下面的方法应比上述解决方案更好地舍入,但是要以性能为代价(由于浮点计算为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;
}

#16 楼

您需要进行浮点除法,然后使用上限函数将值四舍五入到下一个整数。