Reputation: 3
I have a challenge to solve which is slitting a string into evenly-sized chunks.
Examples
Given the string s = "abcdefg"
and chunks = 3
, return ["abc", "de", "fg"]
. Note that the remainder of 1 was distributed to the first element in the list.
Given the string s = "abcdefgh"
and chunks = 3
, return ["abc", "def", "gh"]
. Again, note that the remainder of 2 was distributed to the first element in the list followed by the second element in the list.
So, I have this solution from an old question but the "evenly" isn't consider
public static IEnumerable<string> Iterator(string s, int chunks)
{
for (int i = 0; i < s.Length; i += s.Length - chunks)
{
if (i + chunks > s.Length) chunks = s.Length - i;
yield return s.Substring(i, chunks);
}
}
public static string[] Result(string s, int chunks)
{
if (chunks <= 0)
throw new ArgumentException();
return Iterator(s, chunks).ToArray();
}
Second example would pass with this but the first doesn't, how do I adjust this to pass both test?
Upvotes: -1
Views: 1322
Reputation: 112382
You are confusing the number of chunks with the chunk size.
You must calculate the chunk size with:
int chunkSize = s.Length / chunks;
If the length of the string is not divisible by chunks
, this will truncate the result because integer arithmetic is performed here. E.g., if the string size is 7 and chunks = 3
, then this will yield 2
.
And you have a remainder of 1
. If the string size was 8
, the chunk size would still be 2
, but the remainder would be 2
. Now, you must distribute this remainder among the chunks.
You can get the remainder with the modulo operator %
:
int remainder = s.Length % chunks;
Since you want the first chunks to be bigger, we now attribute this remainder to the first chunks:
int start = 0;
while (start < s.Length)
{
int thisChunkSize = chunkSize;
if (remainder > 0)
{
thisChunkSize++;
remainder--;
}
yield return s.Substring(start, thisChunkSize);
start += thisChunkSize;
}
If you need an even better distribution, you can use floating point arithmetic and round. The MidpointRounding
tells what happens when rounding a value with a .5
fraction.
public static IEnumerable<string> EvenIterator(string s, int chunks)
{
int start = 0;
var rounding = new[] { MidpointRounding.ToPositiveInfinity,
MidpointRounding.ToNegativeInfinity };
int r = 0;
while (start < s.Length) {
int chunkSize = (int)Math.Round((double)(s.Length - start) / chunks, rounding[r]);
r = 1 - r; // Swap the rounding
yield return s.Substring(start, chunkSize);
start += chunkSize;
chunks--;
}
}
A test with "abcdefghijklmno"
and chunk size 6
gives:
[ "abc", "de", "fgh", "ij", "klm", "no" ]
Upvotes: 1