質問
私はINT値のリストを返す関数が値の一部に依存します。
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;
}
.
しかしそれは間違っています。 GetColumn(17,0)
[0,1,2,3,4]を返しますが、戻るはずです[0,1,2,3,4,5]
GetColumn(17,1) - [6,7,8,9,10,11]
GetColumn(17,2) - [12,13,14,15,16]
16の場合は戻ります。
GetColumn(16,0)の場合 - [0,1,2,3,4,5]
GetColumn(16,1) - [6,7,8,9,10]
GetColumn(16,2) - [11,12,13,14,15]
私の関数で何を変えるべきですか?ありがとう!
解決
If this is what you need (numbers increase columnwise but rows need to be filled first):
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
You need to define which column is getting the remainders:
int remainder = total % 3;
if remainder is 1, only first column is 6 elements. if remainder is 2, first & second columns are 6 elements. You need to calculate startIndex and endIndex according to this.
So;
int pageSize = total / 3;
int remainder = total % 3;
int startIndex = column * pageSize + min(column, remainder);
int endIndex = startIndex + pageSize + (remainder > column ? 1 : 0);
should work. I just tested it, it works for different rowsizes than 3.
Here is how I got the formulas, drawing tables is good practice for sorting out such algortihms:
r:Remainder, c:column, ps:pagesize (as calculated above)
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
You can see a pattern if you extend the table for rowsize 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
the value you are adding is the minimum of the related column and remainder
Similarly for the endIndex, desired columns length can be seen when you build a table for given remainder vs column. I won't write that for now because it is taking too much time to draw the tables here and I believe you already got the idea.
他のヒント
The integer division rounds to towards zero. So 17/3 = 5 and -17/3 = -5
I think what you want is to round to the next integer like this
int pageSize = (int)Math.Ceiling(total / 3d);
If I understand correctly the requirement is:
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.
Best thing to do is to make that explicit in your code, and avoid any "clever" logic. The straight-forward splitting boils down to:
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
In c# that would be something like:
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;
}
The answer assumes that we will always divide in 3, and only 3 columns. If the number is variable, the logic to determine the columns can be generalized.