Each Answer to this Q is separated by one/two green lines.

I am trying to figure an elegant way of implementing the distribution of an amount into a given set of slots in python.

For example:

7 oranges distributed onto 4 plates would return:

```
[2, 2, 2, 1]
```

10 oranges across 4 plates would be:

```
[3, 3, 2, 2]
```

Conceptually, what you want to do is compute `7 // 4 = 1`

and `7 % 4 = 3`

. This means that all the plates get 1 whole orange. The remainder of 3 tells you that three of the plates get an extra orange.

The `divmod`

builtin is a shortcut for getting both quantities simultaneously:

```
def distribute(oranges, plates):
base, extra = divmod(oranges, plates)
return [base + (i < extra) for i in range(plates)]
```

With your example:

```
>>> distribute(oranges=7, plates=4)
[2, 2, 2, 1]
```

For completeness, you’d probably want to check that `oranges`

is non-negative and `plates`

is positive. Given those conditions, here are some additional test cases:

```
>>> distribute(oranges=7, plates=1)
[7]
>>> distribute(oranges=0, plates=4)
[0, 0, 0, 0]
>>> distribute(oranges=20, plates=2)
[10, 10]
>>> distribute(oranges=19, plates=4)
[5, 5, 5, 4]
>>> distribute(oranges=10, plates=4)
[3, 3, 2, 2]
```

You want to look at Bresenham’s algorithm for drawing lines (i.e. distributing X pixels on a Y range as “straightly” as possible; the application of this to the distribution problem is straightforward).

This is an implementation I found here:

```
def get_line(start, end):
"""Bresenham's Line Algorithm
Produces a list of tuples from start and end
>>> points1 = get_line((0, 0), (3, 4))
>>> points2 = get_line((3, 4), (0, 0))
>>> assert(set(points1) == set(points2))
>>> print points1
[(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
>>> print points2
[(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
"""
# Setup initial conditions
x1, y1 = start
x2, y2 = end
dx = x2 - x1
dy = y2 - y1
# Determine how steep the line is
is_steep = abs(dy) > abs(dx)
# Rotate line
if is_steep:
x1, y1 = y1, x1
x2, y2 = y2, x2
# Swap start and end points if necessary and store swap state
swapped = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
swapped = True
# Recalculate differentials
dx = x2 - x1
dy = y2 - y1
# Calculate error
error = int(dx / 2.0)
ystep = 1 if y1 < y2 else -1
# Iterate over bounding box generating points between start and end
y = y1
points = []
for x in range(x1, x2 + 1):
coord = (y, x) if is_steep else (x, y)
points.append(coord)
error -= abs(dy)
if error < 0:
y += ystep
error += dx
# Reverse the list if the coordinates were swapped
if swapped:
points.reverse()
return points
```

Mad Physicist answer is perfect. But if you want to distribute the oranges uniformley on the plates (eg. `2 3 2 3`

vs `2 2 3 3`

in the 7 oranges and 4 plates example), here’s an simple idea.

# Easy case

Take an example with 31 oranges and 7 plates for example.

*Step 1*: You begin like Mad Physicist with an euclidian division: `31 = 4*7 + 3`

. Put 4 oranges in each plate and keep the remaining 3.

```
[4, 4, 4, 4, 4, 4, 4]
```

*Step 2*: Now, you have more plates than oranges, and that’s quite different: you have to distribute plates among oranges. You have 7 plates and 3 oranges left: `7 = 2*3 + 1`

. You will have 2 plates per orange (you have a plate left, but it doesn’t matter). Let’s call this `2`

the `leap`

. Start at `leap/2`

will be pretty :

```
[4, 5, 4, 5, 4, 5, 4]
```

# Not so easy case

That was the easy case. What happens with 34 oranges and 7 plates?

*Step 1*: You still begin like Mad Physicist with an euclidian division: `34 = 4*7 + 6`

. Put 4 oranges in each plate and keep the remaining 6.

```
[4, 4, 4, 4, 4, 4, 4]
```

*Step 2*: Now, you have 7 plates and 6 oranges left: `7 = 1*6 + 1`

. You will have one plate per orange. But wait.. I don’t have 7 oranges! Don’t be afraid, I lend you an apple:

```
[5, 5, 5, 5, 5, 5, 4+apple]
```

But if you want some uniformity, you have to place that apple elsewhere! Why not try distribute apples like oranges in the first case? 7 plates, 1 apple : `7 = 1*7 + 0`

. The `leap`

is 7, start at `leap/2`

, that is 3:

```
[5, 5, 5, 4+apple, 5, 5, 5]
```

*Step 3*. You owe me an apple. Please give me back my apple :

```
[5, 5, 5, 4, 5, 5, 5]
```

To summarize : if you have few oranges left, you distribute the peaks, else you distribute the valleys. (*Disclaimer: I’m the author of this “algorithm” and I hope it is correct, but please correct me if I’m wrong !*)

# The code

Enough talk, the code:

```
def distribute(oranges, plates):
base, extra = divmod(oranges, plates) # extra < plates
if extra == 0:
L = [base for _ in range(plates)]
elif extra <= plates//2:
leap = plates // extra
L = [base + (i%leap == leap//2) for i in range(plates)]
else: # plates/2 < extra < plates
leap = plates // (plates-extra) # plates - extra is the number of apples I lent you
L = [base + (1 - (i%leap == leap//2)) for i in range(plates)]
return L
```

Some tests:

```
>>> distribute(oranges=28, plates=7)
[4, 4, 4, 4, 4, 4, 4]
>>> distribute(oranges=29, plates=7)
[4, 4, 4, 5, 4, 4, 4]
>>> distribute(oranges=30, plates=7)
[4, 5, 4, 4, 5, 4, 4]
>>> distribute(oranges=31, plates=7)
[4, 5, 4, 5, 4, 5, 4]
>>> distribute(oranges=32, plates=7)
[5, 4, 5, 4, 5, 4, 5]
>>> distribute(oranges=33, plates=7)
[5, 4, 5, 5, 4, 5, 5]
>>> distribute(oranges=34, plates=7)
[5, 5, 5, 4, 5, 5, 5]
>>> distribute(oranges=35, plates=7)
[5, 5, 5, 5, 5, 5, 5]
```

See also `more_itertools.distribute`

, a third-party tool and its source code.

**Code**

Here we distributes `m`

items into `n`

bins, one-by-one, and count each bin.

```
import more_itertools as mit
def sum_distrib(m, n):
"""Return an iterable of m items distributed across n spaces."""
return [sum(x) for x in mit.distribute(n, [1]*m)]
```

**Demo**

```
sum_distrib(10, 4)
# [3, 3, 2, 2]
sum_distrib(7, 4)
# [2, 2, 2, 1]
sum_distrib(23, 17)
# [2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
```

**Example**

This idea is akin to distributing a deck of cards among players. Here is an initial game of Slapjack

```
import random
import itertools as it
players = 8
suits = list("????")
ranks = list(range(2, 11)) + list("JQKA")
deck = list(it.product(ranks, suits))
random.shuffle(deck)
hands = [list(hand) for hand in mit.distribute(players, deck)]
hands
# [[('A', '?'), (9, '?'), ('K', '?'), (7, '?'), ('A', '?'), (5, '?'), (2, '?')],
# [(6, '?'), ('Q', '?'), (5, '?'), (5, '?'), (3, '?'), (8, '?'), (7, '?')],
# [(7, '?'), (9, '?'), (2, '?'), (9, '?'), (7, '?'), ('K', '?')],
# ...]
```

where the cards are distributed “as equally as possible between all [8] players”:

```
[len(hand) for hand in hands]
# [7, 7, 7, 7, 6, 6, 6, 6]
```

Not sure how this works. But it returns the exact same results

```
a = 23
b = 17
s = pd.Series(pd.cut(mylist, b), index=mylist)
s.groupby(s).size().values
```