Pergunta

Eu tenho uma função que me retorna uma lista de valores int que depende de parte dos valores:

private List<int> GetColumn(int total, int column)
{
    List<int> retList = new List<int>();

    if (total <= 0)
    {
        return retList;
    }

    if (column < 0 || column > 2)
    {
        column = 0;
    }

    int pageSize = total / 3;

    int startIndex = column * pageSize;
    int endIndex = column * pageSize + pageSize;

    if (endIndex > total)
    {
        endIndex = total;
    }

    for (int i = startIndex; i < endIndex; i++)
    {
        retList.Add(i);
    }

    return retList;

}

mas funciona errado, porque para:ObterColuna(17, 0)

retorna [0,1,2,3,4], mas deve retornar [0,1,2,3,4,5]
para GetColumn(17, 1) - [6,7,8,9,10,11]
para GetColumn(17, 2) - [12,13,14,15,16]

para 16 deve retornar:para GetColumn(16, 0) - [0,1,2,3,4,5]
para GetColumn(16, 1) - [6,7,8,9,10]
para GetColumn(16, 2) - [11,12,13,14,15]

O que devo mudar na minha função?Obrigado!

Foi útil?

Solução

Se é isso que você precisa (os números aumentam em colunas, mas as linhas precisam ser preenchidas primeiro):

for 16:
0  6  11
1  7  12
2  8  13
3  9  14
4  10 15
5

for 17:
0  6  12
1  7  13
2  8  14
3  9  15
4  10 16
5  11

Você precisa definir qual coluna está recebendo os restos:

int remainder = total % 3;

se o resto for 1, apenas a primeira coluna terá 6 elementos.se o resto for 2, a primeira e a segunda colunas terão 6 elementos.Você precisa calcular startIndex e endIndex de acordo com isso.

Então;

int pageSize = total / 3;
int remainder = total % 3;

int startIndex = column * pageSize + min(column, remainder);
int endIndex = startIndex + pageSize + (remainder > column ? 1 : 0);

Deveria trabalhar.Acabei de testar, funciona para tamanhos de linha diferentes de 3.

Aqui está como consegui as fórmulas, desenhar tabelas é uma boa prática para resolver esses algoritmos:

r:Remainder, c:column, ps:pagesize (conforme calculado acima)

StartingIndex:
.  |r:0 |r:1   |r:2
----------------------
c:0|0   |0     |0
----------------------
c:1|ps  |ps+1  |ps+1
----------------------
c:2|ps*2|ps*2+1|ps*2+2

Você pode ver um padrão se estender a tabela para o tamanho da linha 4:

StartingIndex:
.  |r:0 |r:1   |r:2   |r:3
------------------------------
c:0|0   |0     |0     |0
------------------------------
c:1|ps  |ps+1  |ps+1  |ps+1
------------------------------
c:2|ps*2|ps*2+1|ps*2+2|ps*2+2
------------------------------
c:3|ps*3|ps*3+1|ps*3+2|ps*3+3

o valor que você está adicionando é o mínimo da coluna relacionada e o restante

Da mesma forma para o endIndex, o comprimento desejado das colunas pode ser visto quando você constrói uma tabela para determinado restante versus coluna.Não vou escrever isso por enquanto porque está demorando muito para desenhar as tabelas aqui e acredito que você já tenha entendido.

Outras dicas

A divisão inteira é arredondada para zero.Então 17/3 = 5 e -17/3 = -5
Eu acho que o que você quer é arredondar para o próximo número inteiro assim

int pageSize = (int)Math.Ceiling(total / 3d);

Se bem entendi, o requisito é:

If the number is 3n,   divide it in 3 groups of n,   n   and n   elements.
If the number is 3n+1, divide it in 3 groups of n+1, n   and n   elements.
If the number is 3n+2, divide it in 3 groups of n+1, n+1 and n   elements.

A melhor coisa a fazer é deixar isso explícito em seu código e evitar qualquer lógica "inteligente".A divisão direta se resume a:

If the number is 3n, the divisions are:
     0 ..  n-1
     n .. 2n-1
    2n .. 3n-1
If the number is 3n+1, the divisions are:
     0 .. n
   n+1 .. 2n
  2n+1 .. 3n
If the number is 3n+2, the divisions are:
     0 .. n
   n+1 .. 2n+1
  2n+2 .. 3n+1

Em c# seria algo como:

public static List<int> Divide3Columns(int total, int column)
{
  int startIndex = 0;
  int endIndex = 0;
  int pageSize = total / 3;

  if (total % 3 == 0)
  {
    startIndex = column * pageSize;
    endIndex = (column + 1) * pageSize - 1;
  }

  if (total % 3 == 1)
  {
    if (column == 0)
    {
      startIndex = 0;
      endIndex = pageSize; //pageSize + 1 elements;
    }
    else
    {
      startIndex = column * pageSize + 1;
      endIndex = (column + 1) * pageSize;
    }
  }

  if (total % 3 == 2)
  {
    if (column == 2)
    {
      startIndex = 2 * pageSize + 2;
      endIndex = 3 * pageSize + 1; //same as total - 1;
    }
    else
    {
      startIndex = column * (pageSize + 1);
      endIndex = (column + 1) * pageSize + column;
    }
  }

  List<int> result = new List<int>();
  for (int i = startIndex; i <= endIndex; i++)
  {
    result.Add(i);
  }
  return result;
}

A resposta pressupõe que sempre iremos divida em 3 e apenas 3 colunas.Se o número for variável, a lógica para determinar as colunas pode ser generalizada.

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