Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I tried to write code to solve the standard Integer Partition problem (Wikipedia). The code I wrote was a mess. I need an elegant solution to solve the problem, because I want to improve my coding style. This is not a homework question.
A smaller and faster than Nolen's function:
def partitions(n, I=1):
yield (n,)
for i in range(I, n//2 + 1):
for p in partitions(n-i, i):
yield (i,) + p
Let's compare them:
In [10]: %timeit -n 10 r0 = nolen(20)
1.37 s ± 28.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [11]: %timeit -n 10 r1 = list(partitions(20))
979 µs ± 82.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [13]: sorted(map(sorted, r0)) == sorted(map(sorted, r1))
Out[14]: True
Looks like it's 1370 times faster for n = 20.
Anyway, it's still far from accel_asc:
def accel_asc(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield a[:k + 2]
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield a[:k + 1]
It's not only slower, but requires much more memory (but apparently is much easier to remember):
In [18]: %timeit -n 5 r2 = list(accel_asc(50))
114 ms ± 1.04 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
In [19]: %timeit -n 5 r3 = list(partitions(50))
527 ms ± 8.86 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
In [24]: sorted(map(sorted, r2)) == sorted(map(sorted, r3))
Out[24]: True
You can find other versions on ActiveState: Generator For Integer Partitions (Python Recipe).
I use Python 3.6.1 and IPython 6.0.0.
While this answer is fine, I'd recommend skovorodkin's answer.
>>> def partition(number):
... answer = set()
... answer.add((number, ))
... for x in range(1, number):
... for y in partition(number - x):
... answer.add(tuple(sorted((x, ) + y)))
... return answer
...
>>> partition(4)
set([(1, 3), (2, 2), (1, 1, 2), (1, 1, 1, 1), (4,)])
If you want all permutations(ie (1, 3) and (3, 1)) change answer.add(tuple(sorted((x, ) + y)) to answer.add((x, ) + y)
I've compared the solution with perfplot (a little project of mine for such purposes) and found that Nolen's top-voted answer is also the slowest.
Both answers supplied by skovorodkin are much faster. (Note the log-scale.)
To to generate the plot:
import perfplot
import collections
def nolen(number):
answer = set()
answer.add((number,))
for x in range(1, number):
for y in nolen(number - x):
answer.add(tuple(sorted((x,) + y)))
return answer
def skovorodkin(n):
return set(skovorodkin_yield(n))
def skovorodkin_yield(n, I=1):
yield (n,)
for i in range(I, n // 2 + 1):
for p in skovorodkin_yield(n - i, i):
yield (i,) + p
def accel_asc(n):
return set(accel_asc_yield(n))
def accel_asc_yield(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield tuple(a[: k + 2])
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield tuple(a[: k + 1])
def mct(n):
partitions_of = []
partitions_of.append([()])
partitions_of.append([(1,)])
for num in range(2, n + 1):
ptitions = set()
for i in range(num):
for partition in partitions_of[i]:
ptitions.add(tuple(sorted((num - i,) + partition)))
partitions_of.append(list(ptitions))
return partitions_of[n]
perfplot.show(
setup=lambda n: n,
kernels=[nolen, mct, skovorodkin, accel_asc],
n_range=range(1, 17),
logy=True,
# https://stackoverflow.com/a/7829388/353337
equality_check=lambda a, b: collections.Counter(set(a))
== collections.Counter(set(b)),
xlabel="n",
)
I needed to solve a similar problem, namely the partition of an integer n into d nonnegative parts, with permutations. For this, there's a simple recursive solution (see here):
def partition(n, d, depth=0):
if d == depth:
return [[]]
return [
item + [i]
for i in range(n+1)
for item in partition(n-i, d, depth=depth+1)
]
# extend with n-sum(entries)
n = 5
d = 3
lst = [[n-sum(p)] + p for p in partition(n, d-1)]
print(lst)
Output:
[
[5, 0, 0], [4, 1, 0], [3, 2, 0], [2, 3, 0], [1, 4, 0],
[0, 5, 0], [4, 0, 1], [3, 1, 1], [2, 2, 1], [1, 3, 1],
[0, 4, 1], [3, 0, 2], [2, 1, 2], [1, 2, 2], [0, 3, 2],
[2, 0, 3], [1, 1, 3], [0, 2, 3], [1, 0, 4], [0, 1, 4],
[0, 0, 5]
]
I'm a bit late to the game, but I can offer a contribution which might qualify as more elegant in a few senses:
def partitions(n, m = None):
"""Partition n with a maximum part size of m. Yield non-increasing
lists in decreasing lexicographic order. The default for m is
effectively n, so the second argument is not needed to create the
generator unless you do want to limit part sizes.
"""
if m is None or m >= n: yield [n]
for f in range(n-1 if (m is None or m >= n) else m, 0, -1):
for p in partitions(n-f, f): yield [f] + p
Only 3 lines of code. Yields them in lexicographic order. Optionally allows imposition of a maximum part size.
I also have a variation on the above for partitions with a given number of parts:
def sized_partitions(n, k, m = None):
"""Partition n into k parts with a max part of m.
Yield non-increasing lists. m not needed to create generator.
"""
if k == 1:
yield [n]
return
for f in range(n-k+1 if (m is None or m > n-k+1) else m, (n-1)//k, -1):
for p in sized_partitions(n-f, k-1, f): yield [f] + p
After composing the above, I ran across a solution I had created almost 5 years ago, but which I had forgotten about. Besides a maximum part size, this one offers the additional feature that you can impose a maximum length (as opposed to a specific length). FWIW:
def partitions(sum, max_val=100000, max_len=100000):
""" generator of partitions of sum with limits on values and length """
# Yields lists in decreasing lexicographical order.
# To get any length, omit 3rd arg.
# To get all partitions, omit 2nd and 3rd args.
if sum <= max_val: # Can start with a singleton.
yield [sum]
# Must have first*max_len >= sum; i.e. first >= sum/max_len.
for first in range(min(sum-1, max_val), max(0, (sum-1)//max_len), -1):
for p in partitions(sum-first, first, max_len-1):
yield [first]+p
Much quicker than the accepted response and not bad looking, either. The accepted response does lots of the same work multiple times because it calculates the partitions for lower integers multiple times. For example, when n=22 the difference is 12.7 seconds against 0.0467 seconds.
def partitions_dp(n):
partitions_of = []
partitions_of.append([()])
partitions_of.append([(1,)])
for num in range(2, n+1):
ptitions = set()
for i in range(num):
for partition in partitions_of[i]:
ptitions.add(tuple(sorted((num - i, ) + partition)))
partitions_of.append(list(ptitions))
return partitions_of[n]
The code is essentially the same except we save the partitions of smaller integers so we don't have to calculate them again and again.
Here is a recursive function, which uses a stack in which we store the numbers of the partitions in increasing order.
It is fast enough and very intuitive.
# get the partitions of an integer
Stack = []
def Partitions(remainder, start_number = 1):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(str(nb_to_add))
Partitions(remainder - nb_to_add, nb_to_add)
Stack.pop()
When the stack is full (the sum of the elements of the stack then corresponds to the number we want the partitions), we print it,
remove its last value and test the next possible value to be stored in the stack. When all the next values have been tested, we pop the last value of the stack again and we go back to the last calling function.
Here is an example of the output (with 8):
Partitions(8)
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1 + 2
1 + 1 + 1 + 1 + 1 + 3
1 + 1 + 1 + 1 + 2 + 2
1 + 1 + 1 + 1 + 4
1 + 1 + 1 + 2 + 3
1 + 1 + 1 + 5
1 + 1 + 2 + 2 + 2
1 + 1 + 2 + 4
1 + 1 + 3 + 3
1 + 1 + 6
1 + 2 + 2 + 3
1 + 2 + 5
1 + 3 + 4
1 + 7
2 + 2 + 2 + 2
2 + 2 + 4
2 + 3 + 3
2 + 6
3 + 5
4 + 4
8
The structure of the recursive function is easy to understand and is illustrated below (for the integer 31):
remainder corresponds to the value of the remaining number we want a partition (31 and 21 in the example above).
start_number corresponds to the first number of the partition, its default value is one (1 and 5 in the example above).
If we wanted to return the result in a list and get the number of partitions, we could do this:
def Partitions2_main(nb):
global counter, PartitionList, Stack
counter, PartitionList, Stack = 0, [], []
Partitions2(nb)
return PartitionList, counter
def Partitions2(remainder, start_number = 1):
global counter, PartitionList, Stack
if remainder == 0:
PartitionList.append(list(Stack))
counter += 1
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(nb_to_add)
Partitions2(remainder - nb_to_add, nb_to_add)
Stack.pop()
Last, a big advantage of the function Partitions shown above is that it adapts very easily to find all the compositions of a natural number (two compositions can have the same set of numbers, but the order differs in this case):
we just have to drop the variable start_number and set it to 1 in the for loop.
# get the compositions of an integer
Stack = []
def Compositions(remainder):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(1, remainder+1):
Stack.append(str(nb_to_add))
Compositions(remainder - nb_to_add)
Stack.pop()
Example of output:
Compositions(4)
1 + 1 + 1 + 1
1 + 1 + 2
1 + 2 + 1
1 + 3
2 + 1 + 1
2 + 2
3 + 1
4
I think the recipe here may qualify as being elegant. It's lean (20 lines long), fast and based upon Kelleher and O'Sullivan's work which is referenced therein:
def aP(n):
"""Generate partitions of n as ordered lists in ascending
lexicographical order.
This highly efficient routine is based on the delightful
work of Kelleher and O'Sullivan.
Examples
========
>>> for i in aP(6): i
...
[1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 2]
[1, 1, 1, 3]
[1, 1, 2, 2]
[1, 1, 4]
[1, 2, 3]
[1, 5]
[2, 2, 2]
[2, 4]
[3, 3]
[6]
>>> for i in aP(0): i
...
[]
References
==========
.. [1] Generating Integer Partitions, [online],
Available: http://jeromekelleher.net/generating-integer-partitions.html
.. [2] Jerome Kelleher and Barry O'Sullivan, "Generating All
Partitions: A Comparison Of Two Encodings", [online],
Available: http://arxiv.org/pdf/0909.2331v2.pdf
"""
# The list `a`'s leading elements contain the partition in which
# y is the biggest element and x is either the same as y or the
# 2nd largest element; v and w are adjacent element indices
# to which x and y are being assigned, respectively.
a = [1]*n
y = -1
v = n
while v > 0:
v -= 1
x = a[v] + 1
while y >= 2 * x:
a[v] = x
y -= x
v += 1
w = v + 1
while x <= y:
a[v] = x
a[w] = y
yield a[:w + 1]
x += 1
y -= 1
a[v] = x + y
y = a[v] - 1
yield a[:w]
# -*- coding: utf-8 -*-
import timeit
ncache = 0
cache = {}
def partition(number):
global cache, ncache
answer = {(number,), }
if number in cache:
ncache += 1
return cache[number]
if number == 1:
cache[number] = answer
return answer
for x in range(1, number):
for y in partition(number - x):
answer.add(tuple(sorted((x, ) + y)))
cache[number] = answer
return answer
print('To 5:')
for r in sorted(partition(5))[::-1]:
print('\t' + ' + '.join(str(i) for i in r))
print(
'Time: {}\nCache used:{}'.format(
timeit.timeit(
"print('To 30: {} possibilities'.format(len(partition(30))))",
setup="from __main__ import partition",
number=1
), ncache
)
)
or https://gist.github.com/sxslex/dd15b13b28c40e695f1e227a200d1646
I don't know if my code is the most elegant, but I've had to solve this many times for research purposes. If you modify the
sub_nums
variable you can restrict what numbers are used in the partition.
def make_partitions(number):
out = []
tmp = []
sub_nums = range(1,number+1)
for num in sub_nums:
if num<=number:
tmp.append([num])
for elm in tmp:
sum_elm = sum(elm)
if sum_elm == number:
out.append(elm)
else:
for num in sub_nums:
if sum_elm + num <= number:
L = [i for i in elm]
L.append(num)
tmp.append(L)
return out
F(x,n) = \union_(i>=n) { {i}U g| g in F(x-i,i) }
Just implement this recursion. F(x,n) is the set of all sets that sum to x and their elements are greater than or equal to n.
There are nearly 14 million combinations from a selection of 6 numbers from a range of 1-49. From the 14 million, I've cut the combinations down to 8.9 million by selecting only those where the sum of the 6 number combination must equate to between 120 and 180.
Example: 5, 10, 20, 27, 29, 40 = 131
Of the remaining 8.9 million combinations, I'm trying to remove all combinations that contain less than 2 and more than 4 odd numbers.
Basically, I want Python to show me how many combinations of those 8.9 million combinations have between 2-4 odd numbers in their combinations. All combinations of only 1 or less odd numbers and 5 or more odd numbers would be excluded from the results.
Example: 5, 10, 20, 27, 32, 40 = 2 odd numbers (it would be included in the amount of combinations).
Thank you!
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
#functools.lru_cache(maxsize=None)
def f(n, l, s):
assert(all(isinstance(v, int) and v >= 0 for v in (n, l, s)))
return 0 if s > _MAX_SUM else (
int(s >= _MIN_SUM) if n == 0 else (
sum(f(n-1, i+1, s+i) for i in range(l, _MAX_NUM+1))
)
)
result = f(_NUM_CHOICES, _MIN_NUM, 0)
print('Number of choices = {}'.format(result))
You can use the combinations() function from itertools and just brutally count the combinations that are eligible:
from itertools import combinations
eligible = 0
for combo in combinations(range(1,50),6):
total = sum(combo)
if total < 120 or total > 180:
continue
odds = sum(n&1 for n in combo)
if odds < 2 or odds > 4:
continue
eligible += 1
print(eligible) # 7221936
It only takes a few seconds (10-12)
You can do almost exactly the same as you are currently doing. Just add a parameter that counts how many odd numbers there are and increase it when you add an odd. Then you can adjust your tests accordingly:
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
_MIN_ODDS = 2
_MAX_ODDS = 4
#functools.lru_cache(maxsize=None)
def f(n, l, s = 0, odds = 0):
if s > _MAX_SUM or odds > _MAX_ODDS:
return 0
if n == 0 :
return int(s >= _MIN_SUM and odds >= _MIN_ODDS)
return sum(f(n-1, i+1, s+i, odds + i % 2) for i in range(l, _MAX_NUM+1))
result = f(_NUM_CHOICES, _MIN_NUM)
print('Number of choices = {}'.format(result))
Because it's memoized and prunes branches, this runs quickly:
150 ns ± 13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Running it with the more managable:
_MIN_SUM = 1
_MAX_SUM = 8
_MIN_NUM = 1
_MAX_NUM = 8
_NUM_CHOICES = 2
_MIN_ODDS = 2
_MAX_ODDS = 4
returns 4 which corresponds to the set:
(1, 3),
(1, 5),
(1, 7),
(3, 5)
Suppose I have decimal numbers between 0 and 2^L. Each of those decimal numbers can be represented as a binary number of length L. I am now interested in a function which takes a single decimal number and then computes all L decimal numbers for which the binary representation only differs in one position. I am interested in the most fast solution for this problem.
Example:
L=3--> Numbers between 0 and 7
F(2) = (0,3,6)
since
2= 010 -> 0=000, 3=011, 6=110
Hope you have an idea and thanks in advance :)
You can use bit-shifts to do this:
def neighbors(n, bitLength):
return map(lambda b: n ^ (1 << b), range(bitLength))
>>> print(list(neighbors(2, 3)))
[3, 0, 6]
They're about the fastest mathematical operation that can be done with a classical computer and for powers of two, they're perfect.
A pure python implementation using the xor operator ^
def neighbors(n, bits):
for bit in range(bits):
yield n ^ (2 ** bit)
It works with your example numbers.
>>> list(neighbors(2, 3))
[3, 0, 6]
Here's a numpy solution that creates an outer product from an sequence of numbers.
import numpy as np
def array_neighbors(numbers, bits=8):
flip_bits = 2 ** np.arange(bits)
return np.bitwise_xor.outer(numbers, flip_bits)
The output is a 2d array with one row for each input number and where the columns correspond to the flipped bit positions.
>>> array_neighbors([0,1,2,3,4,5,6,7], 3)
[[1 2 4]
[0 3 5]
[3 0 6]
[2 1 7]
[5 6 0]
[4 7 1]
[7 4 2]
[6 5 3]]
This is quite fast, and can process a large array of integers in a few milliseconds.
>>> a_million_numbers = np.random.randint(0, 256, 1_000_000)
>>> %timeit array_neighbors(a_million_numbers)
67.8 ms ± 3.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question 8 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I tried to write code to solve the standard Integer Partition problem (Wikipedia). The code I wrote was a mess. I need an elegant solution to solve the problem, because I want to improve my coding style. This is not a homework question.
A smaller and faster than Nolen's function:
def partitions(n, I=1):
yield (n,)
for i in range(I, n//2 + 1):
for p in partitions(n-i, i):
yield (i,) + p
Let's compare them:
In [10]: %timeit -n 10 r0 = nolen(20)
1.37 s ± 28.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [11]: %timeit -n 10 r1 = list(partitions(20))
979 µs ± 82.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [13]: sorted(map(sorted, r0)) == sorted(map(sorted, r1))
Out[14]: True
Looks like it's 1370 times faster for n = 20.
Anyway, it's still far from accel_asc:
def accel_asc(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield a[:k + 2]
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield a[:k + 1]
It's not only slower, but requires much more memory (but apparently is much easier to remember):
In [18]: %timeit -n 5 r2 = list(accel_asc(50))
114 ms ± 1.04 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
In [19]: %timeit -n 5 r3 = list(partitions(50))
527 ms ± 8.86 ms per loop (mean ± std. dev. of 7 runs, 5 loops each)
In [24]: sorted(map(sorted, r2)) == sorted(map(sorted, r3))
Out[24]: True
You can find other versions on ActiveState: Generator For Integer Partitions (Python Recipe).
I use Python 3.6.1 and IPython 6.0.0.
While this answer is fine, I'd recommend skovorodkin's answer.
>>> def partition(number):
... answer = set()
... answer.add((number, ))
... for x in range(1, number):
... for y in partition(number - x):
... answer.add(tuple(sorted((x, ) + y)))
... return answer
...
>>> partition(4)
set([(1, 3), (2, 2), (1, 1, 2), (1, 1, 1, 1), (4,)])
If you want all permutations(ie (1, 3) and (3, 1)) change answer.add(tuple(sorted((x, ) + y)) to answer.add((x, ) + y)
I've compared the solution with perfplot (a little project of mine for such purposes) and found that Nolen's top-voted answer is also the slowest.
Both answers supplied by skovorodkin are much faster. (Note the log-scale.)
To to generate the plot:
import perfplot
import collections
def nolen(number):
answer = set()
answer.add((number,))
for x in range(1, number):
for y in nolen(number - x):
answer.add(tuple(sorted((x,) + y)))
return answer
def skovorodkin(n):
return set(skovorodkin_yield(n))
def skovorodkin_yield(n, I=1):
yield (n,)
for i in range(I, n // 2 + 1):
for p in skovorodkin_yield(n - i, i):
yield (i,) + p
def accel_asc(n):
return set(accel_asc_yield(n))
def accel_asc_yield(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield tuple(a[: k + 2])
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield tuple(a[: k + 1])
def mct(n):
partitions_of = []
partitions_of.append([()])
partitions_of.append([(1,)])
for num in range(2, n + 1):
ptitions = set()
for i in range(num):
for partition in partitions_of[i]:
ptitions.add(tuple(sorted((num - i,) + partition)))
partitions_of.append(list(ptitions))
return partitions_of[n]
perfplot.show(
setup=lambda n: n,
kernels=[nolen, mct, skovorodkin, accel_asc],
n_range=range(1, 17),
logy=True,
# https://stackoverflow.com/a/7829388/353337
equality_check=lambda a, b: collections.Counter(set(a))
== collections.Counter(set(b)),
xlabel="n",
)
I needed to solve a similar problem, namely the partition of an integer n into d nonnegative parts, with permutations. For this, there's a simple recursive solution (see here):
def partition(n, d, depth=0):
if d == depth:
return [[]]
return [
item + [i]
for i in range(n+1)
for item in partition(n-i, d, depth=depth+1)
]
# extend with n-sum(entries)
n = 5
d = 3
lst = [[n-sum(p)] + p for p in partition(n, d-1)]
print(lst)
Output:
[
[5, 0, 0], [4, 1, 0], [3, 2, 0], [2, 3, 0], [1, 4, 0],
[0, 5, 0], [4, 0, 1], [3, 1, 1], [2, 2, 1], [1, 3, 1],
[0, 4, 1], [3, 0, 2], [2, 1, 2], [1, 2, 2], [0, 3, 2],
[2, 0, 3], [1, 1, 3], [0, 2, 3], [1, 0, 4], [0, 1, 4],
[0, 0, 5]
]
I'm a bit late to the game, but I can offer a contribution which might qualify as more elegant in a few senses:
def partitions(n, m = None):
"""Partition n with a maximum part size of m. Yield non-increasing
lists in decreasing lexicographic order. The default for m is
effectively n, so the second argument is not needed to create the
generator unless you do want to limit part sizes.
"""
if m is None or m >= n: yield [n]
for f in range(n-1 if (m is None or m >= n) else m, 0, -1):
for p in partitions(n-f, f): yield [f] + p
Only 3 lines of code. Yields them in lexicographic order. Optionally allows imposition of a maximum part size.
I also have a variation on the above for partitions with a given number of parts:
def sized_partitions(n, k, m = None):
"""Partition n into k parts with a max part of m.
Yield non-increasing lists. m not needed to create generator.
"""
if k == 1:
yield [n]
return
for f in range(n-k+1 if (m is None or m > n-k+1) else m, (n-1)//k, -1):
for p in sized_partitions(n-f, k-1, f): yield [f] + p
After composing the above, I ran across a solution I had created almost 5 years ago, but which I had forgotten about. Besides a maximum part size, this one offers the additional feature that you can impose a maximum length (as opposed to a specific length). FWIW:
def partitions(sum, max_val=100000, max_len=100000):
""" generator of partitions of sum with limits on values and length """
# Yields lists in decreasing lexicographical order.
# To get any length, omit 3rd arg.
# To get all partitions, omit 2nd and 3rd args.
if sum <= max_val: # Can start with a singleton.
yield [sum]
# Must have first*max_len >= sum; i.e. first >= sum/max_len.
for first in range(min(sum-1, max_val), max(0, (sum-1)//max_len), -1):
for p in partitions(sum-first, first, max_len-1):
yield [first]+p
Much quicker than the accepted response and not bad looking, either. The accepted response does lots of the same work multiple times because it calculates the partitions for lower integers multiple times. For example, when n=22 the difference is 12.7 seconds against 0.0467 seconds.
def partitions_dp(n):
partitions_of = []
partitions_of.append([()])
partitions_of.append([(1,)])
for num in range(2, n+1):
ptitions = set()
for i in range(num):
for partition in partitions_of[i]:
ptitions.add(tuple(sorted((num - i, ) + partition)))
partitions_of.append(list(ptitions))
return partitions_of[n]
The code is essentially the same except we save the partitions of smaller integers so we don't have to calculate them again and again.
Here is a recursive function, which uses a stack in which we store the numbers of the partitions in increasing order.
It is fast enough and very intuitive.
# get the partitions of an integer
Stack = []
def Partitions(remainder, start_number = 1):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(str(nb_to_add))
Partitions(remainder - nb_to_add, nb_to_add)
Stack.pop()
When the stack is full (the sum of the elements of the stack then corresponds to the number we want the partitions), we print it,
remove its last value and test the next possible value to be stored in the stack. When all the next values have been tested, we pop the last value of the stack again and we go back to the last calling function.
Here is an example of the output (with 8):
Partitions(8)
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1 + 2
1 + 1 + 1 + 1 + 1 + 3
1 + 1 + 1 + 1 + 2 + 2
1 + 1 + 1 + 1 + 4
1 + 1 + 1 + 2 + 3
1 + 1 + 1 + 5
1 + 1 + 2 + 2 + 2
1 + 1 + 2 + 4
1 + 1 + 3 + 3
1 + 1 + 6
1 + 2 + 2 + 3
1 + 2 + 5
1 + 3 + 4
1 + 7
2 + 2 + 2 + 2
2 + 2 + 4
2 + 3 + 3
2 + 6
3 + 5
4 + 4
8
The structure of the recursive function is easy to understand and is illustrated below (for the integer 31):
remainder corresponds to the value of the remaining number we want a partition (31 and 21 in the example above).
start_number corresponds to the first number of the partition, its default value is one (1 and 5 in the example above).
If we wanted to return the result in a list and get the number of partitions, we could do this:
def Partitions2_main(nb):
global counter, PartitionList, Stack
counter, PartitionList, Stack = 0, [], []
Partitions2(nb)
return PartitionList, counter
def Partitions2(remainder, start_number = 1):
global counter, PartitionList, Stack
if remainder == 0:
PartitionList.append(list(Stack))
counter += 1
else:
for nb_to_add in range(start_number, remainder+1):
Stack.append(nb_to_add)
Partitions2(remainder - nb_to_add, nb_to_add)
Stack.pop()
Last, a big advantage of the function Partitions shown above is that it adapts very easily to find all the compositions of a natural number (two compositions can have the same set of numbers, but the order differs in this case):
we just have to drop the variable start_number and set it to 1 in the for loop.
# get the compositions of an integer
Stack = []
def Compositions(remainder):
if remainder == 0:
print(" + ".join(Stack))
else:
for nb_to_add in range(1, remainder+1):
Stack.append(str(nb_to_add))
Compositions(remainder - nb_to_add)
Stack.pop()
Example of output:
Compositions(4)
1 + 1 + 1 + 1
1 + 1 + 2
1 + 2 + 1
1 + 3
2 + 1 + 1
2 + 2
3 + 1
4
I think the recipe here may qualify as being elegant. It's lean (20 lines long), fast and based upon Kelleher and O'Sullivan's work which is referenced therein:
def aP(n):
"""Generate partitions of n as ordered lists in ascending
lexicographical order.
This highly efficient routine is based on the delightful
work of Kelleher and O'Sullivan.
Examples
========
>>> for i in aP(6): i
...
[1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 2]
[1, 1, 1, 3]
[1, 1, 2, 2]
[1, 1, 4]
[1, 2, 3]
[1, 5]
[2, 2, 2]
[2, 4]
[3, 3]
[6]
>>> for i in aP(0): i
...
[]
References
==========
.. [1] Generating Integer Partitions, [online],
Available: http://jeromekelleher.net/generating-integer-partitions.html
.. [2] Jerome Kelleher and Barry O'Sullivan, "Generating All
Partitions: A Comparison Of Two Encodings", [online],
Available: http://arxiv.org/pdf/0909.2331v2.pdf
"""
# The list `a`'s leading elements contain the partition in which
# y is the biggest element and x is either the same as y or the
# 2nd largest element; v and w are adjacent element indices
# to which x and y are being assigned, respectively.
a = [1]*n
y = -1
v = n
while v > 0:
v -= 1
x = a[v] + 1
while y >= 2 * x:
a[v] = x
y -= x
v += 1
w = v + 1
while x <= y:
a[v] = x
a[w] = y
yield a[:w + 1]
x += 1
y -= 1
a[v] = x + y
y = a[v] - 1
yield a[:w]
# -*- coding: utf-8 -*-
import timeit
ncache = 0
cache = {}
def partition(number):
global cache, ncache
answer = {(number,), }
if number in cache:
ncache += 1
return cache[number]
if number == 1:
cache[number] = answer
return answer
for x in range(1, number):
for y in partition(number - x):
answer.add(tuple(sorted((x, ) + y)))
cache[number] = answer
return answer
print('To 5:')
for r in sorted(partition(5))[::-1]:
print('\t' + ' + '.join(str(i) for i in r))
print(
'Time: {}\nCache used:{}'.format(
timeit.timeit(
"print('To 30: {} possibilities'.format(len(partition(30))))",
setup="from __main__ import partition",
number=1
), ncache
)
)
or https://gist.github.com/sxslex/dd15b13b28c40e695f1e227a200d1646
I don't know if my code is the most elegant, but I've had to solve this many times for research purposes. If you modify the
sub_nums
variable you can restrict what numbers are used in the partition.
def make_partitions(number):
out = []
tmp = []
sub_nums = range(1,number+1)
for num in sub_nums:
if num<=number:
tmp.append([num])
for elm in tmp:
sum_elm = sum(elm)
if sum_elm == number:
out.append(elm)
else:
for num in sub_nums:
if sum_elm + num <= number:
L = [i for i in elm]
L.append(num)
tmp.append(L)
return out
F(x,n) = \union_(i>=n) { {i}U g| g in F(x-i,i) }
Just implement this recursion. F(x,n) is the set of all sets that sum to x and their elements are greater than or equal to n.
I want to print all the prime numbers from 1 to 10 but nothing gets printed when i run the program
c=0
nums = []
k=0
for a in range(1,11):
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
k = k+1
for d in nums:
print nums[d]
I can't figure out why you are using k
and your c should reset in "a" loop and out of "b" loop
code like this:
nums = []
for a in range(1, 11):
c = 0
for b in range(1, 11):
if a % b == 0:
c = c + 1
if c == 2:
nums.append(a)
print nums
You should reset c to zero before the beginning of each inner loop:
nums = []
for a in range(1,11):
c = 0
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
for d in nums:
print d
Additionally, you should use print d, since the for-loop already gives every element in nums.
Using a list comprehension is generally faster and considered more pythonic than using a for-loop.
There are many different ways of calculating prime numbers. Here are some of them.
Here is your original algorithm, with some improvements;
def prime_list(num):
"""Returns a list of all prime numbers up to and including num.
:num: highest number to test
:returns: a list of primes up to num
"""
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in range(3, c, 2))]
return [2] + L
For primes >2, they must be odd numbers. So candidates should contain only odd numbers.
For an odd number c to be prime, one must ensure that c modulo all previous odd numbers (p) must be non-zero.
Lastly, 2 is also prime.
A further improvement is to restrict p up to sqrt(c):
import math
def prime_list2(num):
if num < 3:
raise ValueError('this function only accepts arguments > 2')
candidates = range(3, num+1, 2)
L = [c for c in candidates if all(c % p != 0 for p in
range(3, int(math.sqrt(c))+1, 2))]
return [2] + L
Another implementation:
def prime_list3(num):
num += 1
candidates = range(3, num, 2)
results = [2]
while len(candidates):
t = candidates[0]
results.append(t)
candidates = [i for i in candidates if not i in range(t, num, t)]
return results
This starts off with a list of candidates that contains all odd numbers. Then is calculates a new list of candidates by removing the first number of the previous list and all all multiples of it.
Let's look at the speed of the algorithms.
For small numbers, the original prime_list is the fastest;
In [8]: %timeit prime_list(10)
100000 loops, best of 3: 8.68 µs per loop
In [9]: %timeit prime_list2(10)
100000 loops, best of 3: 10.9 µs per loop
In [10]: %timeit prime_list3(10)
100000 loops, best of 3: 8.96 µs per loop
For larger numbers, prime_list2 comes out the winner:
In [5]: %timeit prime_list(1000)
100 loops, best of 3: 8.28 ms per loop
In [6]: %timeit prime_list2(1000)
100 loops, best of 3: 2.46 ms per loop
In [7]: %timeit prime_list3(1000)
10 loops, best of 3: 23.5 ms per loop
In [11]: %timeit prime_list(10000)
1 loops, best of 3: 646 ms per loop
In [12]: %timeit prime_list2(10000)
10 loops, best of 3: 25.4 ms per loop
In [13]: %timeit prime_list3(10000)
1 loops, best of 3: 2.13 s per loop
I added two print statements to your code - first, under if a%b==0:, I added print a,b; and I print the final value of c after that loop. I get this output:
1 1
1
2 1
2 2
3
3 1
3 3
5
4 1
4 2
4 4
8
5 1
5 5
10
6 1
6 2
6 3
6 6
14
7 1
7 7
16
8 1
8 2
8 4
8 8
20
9 1
9 3
9 9
23
10 1
10 2
10 5
10 10
27
This tells you why you get nothing printed: after the b loop in a == 1, c is 1; after the same loop in the next iteration of the outer loop, c is now 3. So c==2 is never True when that test is made, so nums stays empty.
This also gives you a big hint as to what you need to do to fix it. c keeps increasing, but it should start counting afresh for each iteration of the outer loop - so, move your c=0 to be inside the outer for loop. You also need to change your final print loop to print d instead of print nums[d], or you will get another error. With those changes, your code looks like this:
nums = []
k=0
for a in range(1,11):
c=0
for b in range(1,11):
if a%b==0:
c = c+1
if c == 2:
nums.append(a)
k = k+1
for d in nums:
print d
and it prints
2
3
5
7
as expected.
Your c is not reset to zero inside the loop (the first loop). So set c=0 after line: for a in range(1,11):
I dont know what your k is for. Is it usefull for anything?
Printing the prime numbers dont do nums[d], print d. You are looping on the items not on the indices.
Your code has multiple issues - Every prime number is divisible by 1 so your checks will fail, you are printing nums[d] which is wrong, k is doing nothing, variable nomenclature is too obfuscated, you have unnecessary runs in for loop - you don't need to iterate for all values of b in range, it is sufficient to iterate over existing prime numbers and so on.
Here is how I would write it
primes = [2]
upper_limit = 1000 #find all primes < 1000
for candidate in range(2, upper_limit):
can_be_prime = True
for prime in primes:
if candidate % prime == 0:
can_be_prime = False
break
if can_be_prime:
primes.append(candidate)
print primes
This solution is a little neater:
nums = []
for a in range(2, 101):
for b in range(2, a):
if a % b == 0:
break
else:
nums.append(a)
print nums
Output:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Still, there is no point trying b > sqrt(a).
Try this:
nums = []
k=0
for a in range(2,11):
c=0
for b in range(1,11):
if a%b==0:
c = c+1
if c==2:
nums.append(a)
k = k+1
for d in nums:
print d
You will get
2
3
5
7
Note the code could be more efficient.