Pergunta

Estou pensando principalmente em como exibir controles de paginação ao usar uma linguagem como C# ou Java.

Se eu tiver x itens que desejo exibir em pedaços de sim por página, quantas páginas serão necessárias?

Foi útil?

Solução

Encontrou uma solução elegante:

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

Fonte: Conversão de números, Roland Backhouse, 2001

Outras dicas

Converter para ponto flutuante e vice-versa parece uma grande perda de tempo no nível da CPU.

A solução de Ian Nelson:

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

Pode ser simplificado para:

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

AFAICS, isso não tem o bug de overflow apontado por Brandon DuRette, e como ele é usado apenas uma vez, você não precisa armazenar o recordsPerPage especialmente se ele vier de uma função cara para buscar o valor de um arquivo de configuração ou algo.

Ou sejaisso pode ser ineficiente, se config.fetch_value usasse uma pesquisa de banco de dados ou algo assim:

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

Isso cria uma variável que você realmente não precisa, que provavelmente tem implicações (menores) de memória e é digitada demais:

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

Tudo isso é uma linha e só busca os dados uma vez:

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

Para C# a solução é converter os valores em double (já que Math.Ceiling leva double):

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

Em java você deve fazer o mesmo com Math.ceil().

Isso deve lhe dar o que você deseja.Definitivamente, você desejará x itens divididos por y itens por página. O problema é quando surgem números ímpares; portanto, se houver uma página parcial, também queremos adicionar uma página.

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

A solução matemática de números inteiros fornecida por Ian é boa, mas sofre de um bug de estouro de números inteiros.Supondo que todas as variáveis ​​sejam int, a solução poderia ser reescrita para usar long matemática e evite o bug:

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

Se records é um long, o bug permanece.A solução de módulo não apresenta o bug.

Uma variante de A resposta de Nick Berardi que evita um branch:

int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));

Observação: (-r >> (Integer.SIZE - 1)) consiste no bit de sinal de r, repetido 32 vezes (graças à extensão do sinal do >> operador.) Isso é avaliado como 0 se r é zero ou negativo, -1 se r é positivo.Então, subtraindo isso de q tem o efeito de adicionar 1 se records % recordsPerPage > 0.

Para registros == 0, a solução de rjmunro dá 1.A solução correta é 0.Dito isto, se você sabe que records > 0 (e tenho certeza de que todos assumimos recordsPerPage > 0), então a solução rjmunro fornece resultados corretos e não apresenta nenhum problema de estouro.

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

Todos as soluções matemáticas inteiras serão mais eficientes do que qualquer das soluções de ponto flutuante.

Precisando de um método de extensão:

    public static int DivideUp(this int dividend, int divisor)
    {
        return (dividend + (divisor - 1)) / divisor;
    }

Nenhuma verificação aqui (estouro, DivideByZero, etc), fique à vontade para adicionar, se desejar.A propósito, para aqueles preocupados com a sobrecarga de invocação de métodos, funções simples como essa podem ser incorporadas pelo compilador de qualquer maneira, então não acho que seja esse o motivo.Saúde.

P.S.você também pode achar útil estar ciente disso (o restante fica):

    int remainder; 
    int result = Math.DivRem(dividend, divisor, out remainder);

Outra alternativa é usar a função mod() (ou '%').Se houver um resto diferente de zero, aumente o resultado inteiro da divisão.

Eu faço o seguinte, lida com qualquer estouro:

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

E use esta extensão se houver 0 resultados:

public static bool IsDivisble(this int x, int n)
{
           return (x%n) == 0;
}

Além disso, para o número da página atual (não foi solicitado, mas pode ser útil):

var currentPage = (int) Math.Ceiling(recordsperpage/(double) recordsperpage) + 1;

Alternativa para remover ramificações no teste de zero:

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

Não tenho certeza se isso funcionará em C#, deve funcionar em C/C++.

para C# use a função Math.Ceiling:

var pageCount= Math.Ceiling((double)myList.Count() / recordsPerPage);

e Java usam a função Math.Ceil:

int n = (int) Math.ceil((double)myList.size() / recordsPerPage));

Um método genérico, cujo resultado você pode iterar, pode ser interessante:

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

Eu tive uma necessidade semelhante de converter minutos em horas e minutos.O que usei foi:

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

O seguinte deve fazer o arredondamento melhor do que as soluções acima, mas às custas do desempenho (devido ao cálculo de ponto flutuante de 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;
}

Você desejará fazer a divisão de ponto flutuante e, em seguida, usar a função teto para arredondar o valor para o próximo número inteiro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top