特に、C# や Java などの言語を使用する場合に、ページネーション コントロールを表示する方法を考えています。
1 ページあたりy個のチャンクで表示したいアイテムがx個ある場合、何ページ必要になりますか?
エレガントなソリューションを見つけました:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
浮動小数点への変換とその逆は、CPU レベルでは膨大な時間の無駄に思えます。
イアン・ネルソンの解決策:
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;
これはすべて 1 行で、データを 1 回だけフェッチします。
int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
C# の場合、解決策は値を double にキャストすることです (Math.Ceiling は double を取るため)。
int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
Java では、Math.ceil() で同じことを行う必要があります。
これにより、必要なものが得られるはずです。ページごとに 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 が提供した整数演算ソリューションは優れていますが、整数オーバーフローのバグに悩まされています。変数が 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))
の符号ビットで構成され、 32 回繰り返されます (演算子r
の符号拡張のおかげです)。これは、がゼロまたは負の場合は 0、正の場合は -1 と評価されます。したがって、 からそれを引くと、if に 1 を加える効果があります。>>
r
r
q
records % recordsPerPage > 0
拡張メソッドが必要な場合:
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);
records == 0 の場合、rjmunro の解は 1 を返します。正しい解は 0 です。とはいえ、records > 0 であることがわかっている場合 (そして、recordsPerPage > 0 を想定していると確信している場合)、rjmunro の解は正しい結果を返し、オーバーフローの問題はありません。
int pageCount = 0;
if (records > 0)
{
pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required
すべての整数演算ソリューションは、どの浮動小数点ソリューションよりも効率的です。
もう 1 つの方法は、mod() 関数 (または「%」) を使用することです。ゼロ以外の剰余がある場合は、除算の整数結果をインクリメントします。
あなたが使用することができます
(int)Math.Ceiling(((decimal)model.RecordCount )/ ((decimal)4));
ゼロのテストで分岐を削除する代わりの方法:
int pageCount = (records + recordsPerPage - 1) / recordsPerPage * (records != 0);
これがC#で機能するかどうかわからない場合は、C /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;
}
以下は、上記のソリューションよりも丸めを行う必要がありますが、パフォーマンスが犠牲になります (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;
}
分を時間と分に変換する必要があるのと同様のニーズがありました。私が使用したのは:
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);
浮動小数点除算を行ってから、ceiling 関数を使用して、値を次の整数に切り上げます。