Split number using a maximum amount?

Viewed 88

I'm a bit stuck in this:

Let's say I want to have 45 items of something, but the maximum stack I can have of that item is 10. So I want a collection that returns me [10, 10, 10, 10, 5] based on that.

This is what I currently have. (yes, I have to use unsigned int16 for my project, but it doesn't matter if your example is regular integer).

ushort Ceiling = (ushort)Math.Ceiling((double)Amount / (double)MaxStackSize);
ushort[] Sizes = new ushort[Ceiling];

for (ushort i = 0; i < Ceiling; i++)
{
    if (Amount != MaxStackSize && i == Ceiling - 1)
    {
        Sizes[i] = (ushort)(Amount % MaxStackSize);
    }
    else
    {
        Sizes[i] = MaxStackSize;
    }
}

It works to a certain degree, but sometimes the module will return 0. (for example 10 % 10 or 30 % 10). Or maybe there's a better way to do this instead of what I'm doing. I'll appreciate the help!

2 Answers

Using LINQ the next approach can be used:

using System.Linq;


ushort Amount = 45;
ushort MaxStackSize = 10;

ushort div = (ushort) (Amount / MaxStackSize);
ushort mod = (ushort) (Amount % MaxStackSize);

ushort[] Sizes;

if (mod == 0)
{
    Sizes = Enumerable.Repeat<ushort>(MaxStackSize, div).ToArray();
}
else
{
    Sizes = Enumerable.Repeat<ushort>(MaxStackSize, div).Concat(new ushort[] {mod}).ToArray();
}

Here is complete sample.


UPDATE:

@Gimly pointed out in the comment:

I wouldn't even put the else, the first part in both your if and else is repeated, so you could always do the first part and only do the Concat part in the if (reversed).

Here is a modified solution, using @Gimly's hint:

using System.Collections.Generic;
using System.Linq;


ushort Amount = 45;
ushort MaxStackSize = 10;

ushort div = (ushort) (Amount / MaxStackSize);
ushort mod = (ushort) (Amount % MaxStackSize);

IEnumerable<ushort> result = Enumerable.Repeat<ushort>(MaxStackSize, div);

if (mod != 0)
    result = result.Concat(new ushort[] {mod});

ushort[] Sizes = result.ToArray();

Here is complete sample.

Pretty much the same as Turdashev answer but using regular loops. At least for me, it's easier to understand the idea this way. It's important to ouline edgecases which potentally can make your problem more difficul. Do you need to validate the amount, the maxSize? Is it possible to have more packages than it's allowed to return (For example maxSize is 2 items per package and you have 1 million items, is that OK?) and stuff like that. Other than that here is the loop variant:

    public static List<int> Packages(int amount)
    {
        var packages = new List<int>();
        var maxSize = 10;

        if (amount <= maxSize)
        {
            packages.Add(amount);
            return packages;
        }

        var fullPackages = amount / maxSize;
        var rest = amount - (fullPackages * maxSize);

        for (var i = 0; i < fullPackages; i++)
        {
            packages.Add(maxSize);
        }

        if (rest > 0)
        {
            packages.Add(rest);
        }

        return packages;
    }
Related