特に、C#やJavaなどの言語を使用している場合に、ページネーションコントロールを表示する方法について考えています。
ページごとにyのチャンクで表示するxアイテムがある場合、いくつのページが必要になりますか?
x
で割り切れる場合y
、y/x + 1
高すぎます。
特に、C#やJavaなどの言語を使用している場合に、ページネーションコントロールを表示する方法について考えています。
ページごとにyのチャンクで表示するxアイテムがある場合、いくつのページが必要になりますか?
x
で割り切れる場合y
、y/x + 1
高すぎます。
回答:
エレガントなソリューションを見つけました:
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が指摘したオーバーフローバグはありません。これは1回しか使用しないため、構成ファイルから値をフェッチするための高価な関数から取得したり、特別に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;
これはすべて1行で、データを1回だけフェッチします。
int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
-1 / 1 + 1 = 0
。これは非常に一般的なことではありませんが、ユーザーがページサイズを調整できるようにする場合は注意が必要です。したがって、ユーザーがページサイズ1を許可しないようにするか、ページサイズをチェックするか、またはその両方を行います(おそらく予期しない動作を回避するために推奨されます)。
C#の場合の解決策は、値をdoubleにキャストすることです(Math.Ceilingはdoubleを取るため)。
int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
Javaでは、Math.ceil()で同じことを行う必要があります。
int
ため、出力をキャストする必要もあります。Math.Ceiling
double
decimal
これはあなたが望むものを与えるはずです。ページごとにxアイテムをyアイテムで割ったものが確実に必要になります。問題は不均一な数が発生した場合です。そのため、部分的なページがある場合は、1ページも追加する必要があります。
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が提供した整数演算ソリューションは優れていますが、整数オーバーフローのバグに悩まされています。変数がすべて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
if 1が加算されrecords % recordsPerPage > 0
ます。
records == 0の場合、rjmunroの解は1を返します。正しい解は0です。つまり、records> 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にする必要があります)。これは、正解または関数のインターフェースから明確でない非負の整数に対してのみ正しいです。
もう1つの方法は、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;
}
Lists.partition(List, int)
)があり、皮肉なことsize()
に、結果List
(の時点でr09
)の方法は、ブランドンデュレットの回答で言及されたオーバーフローバグの影響を受けます。
私は、分を時間と分に変換する必要があるのと同じようなニーズがありました。私が使ったのは:
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;
}