Sums of digits 1 through 7
Pyth, 18 14 bytes
hfqSjkTjkS7./Q
Thanks to @isaacg for golfing off 2 bytes and paving the way for 2 more.
The code will crash if it should produce no output, which causes no output to be produced.
This will work for small-ish inputs if you're patient enough, and for larger ones if given enough time and memory.
To verify that the code works as intended, you can replace the 7
with a 3
for sums of digits 1 through 3. Click here for a test suite.
Example runs
$ time pyth/pyth.py -c 'hfqSjkTjkS7./Q' <<< 28
(1, 2, 3, 4, 5, 6, 7)
real 4m34.634s
user 4m34.751s
sys 0m0.101s
$ time pyth/pyth.py -c 'hfqSjkTjkS7./Q' <<< 29 2>/dev/null
real 9m5.819s
user 9m6.069s
sys 0m0.093s
How it works
./Q Compute all integer partitions of the input.
f Filter the integer partitions:
jkT Join the integers with empty separator.
S Sort the characters of the resulting string.
jkS7 Join [1, ..., 7] with empty separator.
q Check both results for equality.
Keep the partition of `q' returned True.
h Retrieve the first element of the filtered list.
For a non-empty list, this retrieves the solution.
For the empty list, it causes an error and produces no output.
Python 3, 109
def f(n,s=set('1234567'),l='0,'):[f(n,s-{x},l+x+c)for c in(',','')for x in s]or n-sum(eval(l))or~print(l[2:])
A function that takes a number and outputs a tuple in the like 123,4567,
. Yes, this is a valid tuple.
The idea is to generate all possible strings like 43,126,7,5,
that have the digits 1
through 7
separated by commas, with no two commas consecutive. Evaluate this expression as a tuple, and its sum equals n
, print it and terminate with error.
To build all such strings, we track the set s
of chars to use, and try appenping each one either with a comma, which makes the digit end the entry, or without, in which case future digits will concatenate onto it.
Short-circuiting is used to check that s
is empty because the list-comp is empty, and that n==sum(eval(l))
, in which case we print l
and terminate with an error by taking ~
of the None
returned by printing (thanks to Sp3000 for this.).
I believe that in Python 3.5, two chars can be saved by writing s={*'1234567'}
(thanks Sp3000).
There's some small annoyances that eat up chars. One is that in the case that l
looking like 1234567
with no commas, it is parsed as a single number and calling sum
gives an error. This is handled with the hack of starting l
with the element 0
and stripping it when printing. This costs 6 chars.
Iterating c
over the comma and the empty string is annoyingly wordy for c in(',','')
, since Python 3 doesn't allow this tuple to be naked. I'd like there to be some char ?
that is ignored in numbers to do ',?'
for 4 chars less, but there doesn't seem to be such a char.
Old method:
Python 2, 117
def f(n,s={1,2,3,4,5,6,7},l=[],p=0):
if{n,p}|s=={0}:print l;1/0
if p:f(n-p,s,l+[p])
for x in s:f(n,s-{x},l,p*10+x)
Defines a function that takes a number and prints a list.
The idea is to use recursion to try every branch. The variables track are
- The remaining sum
n
needed - The set of digits
s
remaining to use - The list
l
of numbers made so far - The current partially-formed number
p
When n==0
and s
is empty, print l
and terminate by error.
If the current partially-formed number p
is non-zero, try adding it to the list and removing it from the remaining sum.
For each digit x
we can use from s
, try appending it to p
and removing it from s
.
Pyth, 23
#iRThfqQsiR10Ts./M.pS7q
Naive brute force, too slow online, takes about a minute on my computer. Uses the common "loop forever until exception" pattern of pyth golfs where accessing the resulted filtered list of combinations causes an error for impossible numbers, like 29
.
Outputs like a pythonic list, e.g.
1891
[1234, 657]
100
[1, 2, 34, 56, 7]
370
[12, 345, 6, 7]
Here is a paste of all of the 10136 numbers that can be made this way.