Luke Puplett
Luke Puplett

Reputation: 45253

How can I distribute x items as evenly as possible across y columns?

I have a collection of items. I also have a dynamic number of columns that may change.

I need an algorithm that will redistribute my items into buckets such that I can bind them to the UI. I would like to fill down and then across, but in a manner that fills the width first.

I'd like the most even and 'rectangular' distribution as possible.

This arrangement is wrong since it doesn't fill column 9.

            1 2 3 4 5 6 7 8 9

            A D G J M P S V
            B E H K N Q T 
            C F I L O R U

This arrangement is correct, though less desirable...

            1 2 3 4 5 6 7 8 9

            A D G J M P S U V
            B E H K N Q T
            C F I L O R

...than this one, which is visually more balanced.

            1 2 3 4 5 6 7 8 9

            A D G J M O Q S U
            B E H K N P R T V
            C F I L 

Thanks. This is Q&A, I solved it already.

Upvotes: 3

Views: 846

Answers (1)

Luke Puplett
Luke Puplett

Reputation: 45253

This will balance items across buckets with a 'left side bias'.

    public static T[][] FillBucketsEvenly<T>(IEnumerable<T> items, int bucketCount)
    {
        int itemsPerBucket = items.Count() / bucketCount;
        int countOfBucketsTakingExtraOne = items.Count() % bucketCount;

        T[][] buckets = new T[bucketCount][];

        // Build empty array structure.

        for (int i = 0; i < bucketCount; i++)
        {
            if (i < countOfBucketsTakingExtraOne)
            {
                buckets[i] = new T[itemsPerBucket + 1];
            }
            else
            {
                buckets[i] = new T[itemsPerBucket];
            }
        }

        // Fill the structure.

        int itemsAdded = 0;
        foreach(var bucket in buckets)
        {
            int grabSize = bucket.Count();

            var grab = items.Skip(itemsAdded).Take(grabSize);
            for (int i = 0; i < grabSize; i++)
            {
                bucket[i] = grab.ElementAt(i);
            }

            itemsAdded += grabSize;
        }

        return buckets;
    }

Upvotes: 2

Related Questions