Reputation: 325
How can, efficiently, a number be evenly distributed in 'n' groups?
I thought of this function, but it doesn't divide completely evenly this numbers.
def DivideList(total_num, div_num):
div = int(total_num)/int(div_num)
if (div_num < total_num):
div_list = [[div*i, div*(i+1)] for i in range(div_num)]
div_list[div_num-1][1] = total_num
else:
div_list = [[i, i+1] for i in range(total_num)]
return div_list
print DivideList(100, 8)
Could this also be achieved with list comprehension?
EDIT:
Example:
DivideList(20, 4) >> [[0, 5], [5, 10], [10, 15], [15, 20]]
DivideList(14, 4) >> [[0, 4], [4, 8], [8, 11], [11, 14]]
Upvotes: 1
Views: 1748
Reputation: 1987
Example1:
def DivideList(total_num, div_num):
div = total_num / div_num
left = total_num - div * div_num
result = []
m = 0
for i in xrange(left):
k = m
m += (div + 1)
result.append([k, m])
for i in xrange(div_num - left):
k = m
m += div
result.append([k, m])
return result
More concise:
def DivideList(total_num, div_num):
div = total_num / div_num
left = total_num - div * div_num
result = []
for i in xrange(0, left*(div+1), div+1):
result.append([i, i+div+1])
for i in xrange(left*(div+1), total_num, div):
result.append([i, i+div])
return result
Example2: Here's a generator that yields the chunks you want:
def DivideList(total_num, div_num):
div = total_num / div_num
left = total_num - div * div_num
m = 0
for i in xrange(left):
k = m
m += (div + 1)
yield [k, m]
for i in xrange(div_num - left):
k = m
m += div
yield [k, m]
More concise:
def DivideList(total_num, div_num):
div = total_num / div_num
left = total_num - div * div_num
for i in xrange(0, left*(div+1), div+1):
yield [i, i+div+1]
for i in xrange(left*(div+1), total_num, div):
yield [i, i+div]
Upvotes: 1
Reputation: 435
Old suggestion:
So if you are simply trying to force a float division, change your code as
div = 1.0*total_num/div_num
EDIT: So I am still unclear on your requirement, but my attempt is below. Also, does it have to be list comprehensions? really affects readability in this case. I managed to implement it in two list comprehensions.
def Segments(total_num,div_num):
return [(total_num/div_num)+1 if(i<total_num%div_num) else (total_num/div_num) for i in range(div_num)]
def DivideList(series):
return [[sum(series[0:i]),sum(series[0:i+1])] for i in range(len(series))]
print DivideList(Segments(100,8))
Maybe someone can shorten/beautify this further.
Upvotes: 0
Reputation: 8254
Here is one possibility for achieving the result. Please specify the corner cases you wish to handle, if this is not sufficient. For instance, it does not make sense to cast to int
if the expected arguments are already int
s, as in your example.
As suggested by ma3oun, np.linspace
is an excellent way to achieve this:
>>> def divide_list(total_num, div_num):
... temp = np.linspace(0, total_num, div_num + 1)
... return list(zip(temp[:-1], temp[1:]))
...
>>> divide_list(100, 8)
[(0.0, 12.5), (12.5, 25.0), (25.0, 37.5), (37.5, 50.0), (50.0, 62.5), (62.5, 75.0), (75.0, 87.5), (87.5, 100.0)]
This produces even steps, unlike your last example:
>>> divide_list(20, 4)
[(0.0, 5.0), (5.0, 10.0), (10.0, 15.0), (15.0, 20.0)]
>>> divide_list(14, 4)
[(0.0, 3.5), (3.5, 7.0), (7.0, 10.5), (10.5, 14.0)]
My previous example using np.arange
:
>>> import numpy as np
>>> def divide_list(total_num, div_num):
... div = total_num / div_num
... temp = np.arange(0, total_num + div, div)
... return list(zip(temp[:-1], temp[1:]))
...
>>> divide_list(100, 8)
[(0.0, 12.5), (12.5, 25.0), (25.0, 37.5), (37.5, 50.0), (50.0, 62.5), (62.5, 75.0), (75.0, 87.5), (87.5, 100.0)]
Upvotes: 0