Related
How can I write a recursive backtracking function count(N,S) in which it prints all N-digit numbers such that the sum of each 3 consecutive digits in the number is exactly equal to S where N will be less than or equal to 10, and is from 0 to 27.
Code:
def count(S):
n = int(S)
if n % 3 == 0:
print(int(n / 3 - 1),int(n / 3),int(n / 3 + 1))
else:
print(None)
S = 27
count(S)
Sample Output:
8 9 10
I'm quite confused on how can I write this recursively.
Your current function is not recursive. To make it recursive, you'd basically have to call count(n-1, s) somewhere within the execution of count(n, s). One way to do it would be like this:
if n > 1, get possible solutions for n-1 and append any digit that still satisfied the condition
if n == 0 just return "" (it's a bit easier if the function returns strings, not actual integers)
As a generator function, this could look somewhat like this. Of course, you can just as well collect the results in a list and return them, or just get the count of such numbers and return that.
def count(n, s):
if n > 0:
for x in count(n-1, s):
for d in range(10):
y = str(d) + x
if len(y) < 3 or sum(map(int, y[:3])) == s:
yield y
else:
yield ""
for x in count(5, 15):
print(x)
So I have very, very limited coding knowledge and half the code I used here I learned today but what I was attempting to do was to create a list that was 2020 positive whole numbers long and which excluded all numbers that were divisible by 3 or 4 but not by 5. I was trying to figure out what the 2020th number was but I noticed that in my final list with the numbers excluded, it was still leaving them in towards the end!
This is the code I wrote:
numbers = [*range(1, 2165, 1)]
#print(numbers)
list1 = [ x for x in range(1, 2165) if x % 3 == 0 and x % 4 == 0 and x % 5 != 0 ]
#print(list1)
for x in list1:
numbers.remove(x)
print(len(numbers))
print(numbers)
Like I said I'm not very good at coding but it did seem to be working early on in the list as 12 was excluded and 60 was left in but towards the end, 2139 was left, which is divisible by 3.
I would appreciate any help.
2020 positive whole numbers long
For things like this, rather than iterating over a fixed range (in your case, from 1 to 2165, which doesn't produce 2020 numbers matching your conditions), it's usually more straightforward to build a generator that gives you numbers that you want, and take numbers from it via next() until you have as many as you need. In this case, given your conditions
def my_generator():
x = 0
while True:
x += 1
# skip all numbers that are divisible by (3 or 4) but are not divisible by 5
if ((x % 3 == 0) or (x % 4 == 0)) and (x % 5) != 0:
continue
yield x
# initialize the generator, and then grab exactly 2020 numbers from it
gen = my_generator()
numbers = [next(gen) for _ in range(2020)]
print("The 2020th number meeting the conditions is", numbers[-1])
# 3367
Note that, in your original question, your if condition was coded incorrectly, and I've fixed it here.
It might simplify your debugging if you just built the list directly by explicitly declaring the condition you're trying to match on rather than doing it in multiple steps. You can generate numbers in a single comprehension:
[x for x in range(1, 2165) if not(x % 3 == 0 and x % 4 == 0 and x % 5 != 0)]
or the logical equivalent:
[x for x in range(1, 2165) if x % 3 != 0 or x % 4 != 0 or x % 5 == 0]
If you're not convinced this is the same, you can test it against the numbers list generated by your original code:
>>> numbers == [x for x in range(1, 2165) if not(x % 3 == 0 and x % 4 == 0 and x % 5 != 0)]
True
2139 appears in this list because 2139 % 4 != 0.
If this doesn't match the condition you're trying to capture, having the code simplified should make it easier to find and fix the problem.
While writing a python program for calculating the sum of primes between 2 to n (both inclusive), I am getting the error "The generator is not callable"
Can anyone help with the error or suggest what am I missing here?
n = int(input())
sum = 0
sum = sum(list(filter((lambda n: n%y != 0 for y in range(2, n)), range(2, n+1))))
print(sum)
1. first error: "TypeError: 'generator' object is not callable"
this error raise because you pass to filter build-in method a generator, you "cover" the lambda method with parentheses:
filter((lambda n: n%y != 0 for y in range(2,n)), range(2,n+1))
Solution: "uncover" the parentheses
filter(lambda n: n%y != 0 for y in range(2,n), range(2,n+1))
2. second error: "SyntaxError: Generator expression must to be
parenthesized":
lambda n: n%y != 0 for y in range(2,n)
the error is clear: n%y != 0 for y in range(2,n) is a generator and needs to be be parenthesized,
here you want to test if the number is a prime so you want to check if all the values from your generator are True
Solution: use the build-in method all
lambda n: all(n%y != 0 for y in range(2,n))
3. last error: "TypeError: 'int' object is not callable"
sum=0
this is happening because you are using sum build-in method name for your variable sum, so the sum is not anymore the built-in method but an integer
Solution: another name for your variable:
n_prime_sum = 0
here is your code with the fixes:
n = int(input())
n_prime_sum = 0
n_prime_sum = sum(list(filter(lambda n: all(n%y != 0 for y in range(2,n)), range(2,n+1))))
n_prime_sum
# n = 10
output:
17
also, you can define a function that generates all the prime btw 2 and n (both inclusive) then apply the sum build-in method on this function:
# original code by David Eppstein, UC Irvine, 28 Feb 2002
# with comments by Eli Bendersky, https://stackoverflow.com/a/568618
def gen_primes(n):
"""Much more efficient prime generation, the Sieve of Eratosthenes"""
D = {}
q = 2 # The running integer that's checked for primeness
while q <= n:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
#
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
n = int(input())
n_prime_sum = sum(gen_primes(n))
print(n_prime_sum)
# n = 10
output:
17
most of the code for the function gen_prime comes from here
Well, in my imagination this approach being optimal would
only divide with (already) known primes (and not every number)
up to the square root of the given number
import math
primes=[2]
def isprime(n): # NB! this is fragile,
s=int(math.sqrt(n)) # relies on `primes` being
for p in primes: # already fully grown
if n%p==0: # up to the sqrt(n)
return False
if p>s:
return True
maxn=19
for i in range(3,maxn+1):
if isprime(i):
primes.append(i)
print(primes)
print(sum(primes))
Then comes the uglification make it lambda part
isprime=lambda n:all(n%p!=0 for p in primes)
works, but it misses the sqrt magic, then
isprime=lambda n:all(n%p!=0 for p in (p for p in primes if p<=int(math.sqrt(n))))
which calculates int(math.sqrt(n)) for all known primes, but that could be a one-time parameter instead, either for a filter() or for an innner lambda (this latter one is shown here):
isprime=lambda n:all(n%p!=0 for p in (lambda s:(p for p in primes if p<=s))(int(math.sqrt(n))))
I still do not like the fact that it compares all primes to s, stopping in the middle may be more efficient, getting a slice with index(next(...)) can do that:
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
just it remains ugly that next() and index() traverse a part of the list twice.
Then comes the outer loop, I would use reduce() for that from functools, as the accumulator of the reduction could be the actual list of primes, and then it would not be a separate variable.
Step 0 would be making it in a minimalist way, still with the variable primes lying around, but using the terrible trick with tuples, (do,some,things,result)[3] will do the things, and evaluate to the result:
primes=[2]
isprime=lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))])
maxn=19
ps=functools.reduce(lambda primes,n:(primes.append(n) if isprime(n) else None,primes)[1],range(3,maxn+1),primes)
print(ps)
print(primes)
print(sum(primes)) # ps and primes are the same list actually
and then finalize the monster:
import math
import functools
plist=lambda maxn:functools.reduce(lambda primes,n:(primes.append(n) if (lambda n:all(n%p!=0 for p in primes[:(lambda s:primes.index(next(p for p in primes if p>s)))(int(math.sqrt(n)))]))(n) else None,primes)[1],range(3,maxn+1),[2])
primes=plist(19)
print(primes)
print(sum(primes))
Test: https://ideone.com/0y7dN9
Output:
[2, 3, 5, 7, 11, 13, 17, 19]
77
The takeaway message would be: lambdas can be useful, but actually you do not always have to use them.
A slightly cleaner version:
n = int(input())
nums = range(2, n + 1)
for i in range(2, n + 1):
nums = list(filter(lambda x: x == i or x % i, nums))
print(sum(nums))
You can also write it like this with list comprehension:
from math import sqrt, floor
sum(( p
for p in range(2, n+1)
if all( p%q != 0 for q in range(2, floor(sqrt(p))+1) ) ))
You don't need to check all the numbers, just the ones until the square root of the own number.
Example: You can find out that 10 = 2 * 5 is non a prime by checking 10 % 2 == 0 or 10 % 5 == 0. With the square root limit, you'd only check until 3, but that's fine since you'd already have seen the 2, and defined 10 as not prime.
If this application is for you to explore, you might want to check the sieve of Eratosthenes algorithm to find the prime numbers, which is considered one of the most efficient ways to find small primes.
However, if you just need to find the primes and sum them, you can always use a library like gmpy2. Check this answer to know more.
Your solution is almost correct. But you need to use all inside the lambda function, because you want all the n%y != 0 statements to be true:
sum(list(filter((lambda n: all(n%y != 0 for y in range(2,n))), range(2,n+1))))
As pointed out in the comments, you could improve the efficiency of your code by checking only the divisors which are not greater than the square root of the number:
import math
sum(list(filter((lambda n: all(n%y != 0 for y in range(2,int(math.sqrt(n))+1))), range(2,n+1))))
Explanation
n%y != 0 for y in range(2,n) is a generator, not a boolean value!
all(n%y != 0 for y in range(2,n)) is a boolean value corresponding to n%2 != 0 and n%3 != 0 and ... and n%(n-1) != 0
After reading all the answers and trying/testing myself, I have redesigned the answer, which you can modify as per your need:
# get the user input
n = int(input())
from functools import reduce
# create a list with all the primes within the input number range
n_prime = range(2, n + 1)
for i in range(2, n + 1):
n_prime = list(filter(lambda x: x == i or x % i, n_prime))
# print the list of primes obtained from above
print(n_prime)
# let's add all these numbers in the above list and print the summed value
sum_n_prime = reduce(lambda x, y : x + y, n_prime)
print(sum_n_prime)
What I'm looking to do:
I need to make a function that, given a list of positive integers (there can be duplicate integers), counts all triples (in the list) in which the third number is a multiple of the second and the second is a multiple of the first:
(The same number cannot be used twice in one triple, but can be used by all other triples)
For example, [3, 6, 18] is one because 18 goes evenly into 6 which goes evenly into 3.
So given [1, 2, 3, 4, 5, 6] it should find:
[1, 2, 4] [1, 2, 6] [1, 3, 6]
and return 3 (the number of triples it found)
What I've tried:
I made a couple of functions that work but are not efficient enough. Is there some math concept I don't know about that would help me find these triples faster? A module with a function that does better? I don't know what to search for...
def foo(q):
l = sorted(q)
ln = range(len(l))
for x in ln:
if len(l[x:]) > 1:
for y in ln[x + 1:]:
if (len(l[y:]) > 0) and (l[y] % l[x] == 0):
for z in ln[y + 1:]:
if l[z] % l[y] == 0:
ans += 1
return ans
This one is a bit faster:
def bar(q):
l = sorted(q)
ans = 0
for x2, x in enumerate(l):
pool = l[x2 + 1:]
if len(pool) > 1:
for y2, y in enumerate(pool):
pool2 = pool[y2 + 1:]
if pool2 and (y % x == 0):
for z in pool2:
if z % y == 0:
ans += 1
return ans
Here's what I've come up with with help from y'all but I must be doing something wrong because it get's the wrong answer (it's really fast though):
def function4(numbers):
ans = 0
num_dict = {}
index = 0
for x in numbers:
index += 1
num_dict[x] = [y for y in numbers[index:] if y % x == 0]
for x in numbers:
for y in num_dict[x]:
for z in num_dict[y]:
print(x, y, z)
ans += 1
return ans
(39889 instead of 40888) - oh, I accidentally made the index var start at 1 instead of 0. It works now.
Final Edit
I've found the best way to find the number of triples by reevaluating what I needed it to do. This method doesn't actually find the triples, it just counts them.
def foo(l):
llen = len(l)
total = 0
cache = {}
for i in range(llen):
cache[i] = 0
for x in range(llen):
for y in range(x + 1, llen):
if l[y] % l[x] == 0:
cache[y] += 1
total += cache[x]
return total
And here's a version of the function that explains the thought process as it goes (not good for huge lists though because of spam prints):
def bar(l):
list_length = len(l)
total_triples = 0
cache = {}
for i in range(list_length):
cache[i] = 0
for x in range(list_length):
print("\n\nfor index[{}]: {}".format(x, l[x]))
for y in range(x + 1, list_length):
print("\n\ttry index[{}]: {}".format(y, l[y]))
if l[y] % l[x] == 0:
print("\n\t\t{} can be evenly diveded by {}".format(l[y], l[x]))
cache[y] += 1
total_triples += cache[x]
print("\t\tcache[{0}] is now {1}".format(y, cache[y]))
print("\t\tcount is now {}".format(total_triples))
print("\t\t(+{} from cache[{}])".format(cache[x], x))
else:
print("\n\t\tfalse")
print("\ntotal number of triples:", total_triples)
Right now your algorithm has O(N^3) running time, meaning that every time you double the length of the initial list the running time goes up by 8 times.
In the worst case, you cannot improve this. For example, if your numbers are all successive powers of 2, meaning that every number divides every number grater than it, then every triple of numbers is a valid solution so just to print out all the solutions is going to be just as slow as what you are doing now.
If you have a lower "density" of numbers that divide other numbers, one thing you can do to speed things up is to search for pairs of numbers instead of triples. This will take time that is only O(N^2), meaning the running time goes up by 4 times when you double the length of the input list. Once you have a list of pairs of numbers you can use it to build a list of triples.
# For simplicity, I assume that a number can't occur more than once in the list.
# You will need to tweak this algorithm to be able to deal with duplicates.
# this dictionary will map each number `n` to the list of other numbers
# that appear on the list that are multiples of `n`.
multiples = {}
for n in numbers:
multiples[n] = []
# Going through each combination takes time O(N^2)
for x in numbers:
for y in numbers:
if x != y and y % x == 0:
multiples[x].append(y)
# The speed on this last step will depend on how many numbers
# are multiples of other numbers. In the worst case this will
# be just as slow as your current algoritm. In the fastest case
# (when no numbers divide other numbers) then it will be just a
# O(N) scan for the outermost loop.
for x in numbers:
for y in multiples[x]:
for z in multiples[y]:
print(x,y,z)
There might be even faster algorithms, that also take advantage of algebraic properties of division but in your case I think a O(N^2) is probably going to be fast enough.
the key insight is:
if a divides b, it means a "fits into b".
if a doesn't divide c, then it means "a doesn't fit into c".
And if a can't fit into c, then b cannot fit into c (imagine if b fitted into c, since a fits into b, then a would fit into all the b's that fit into c and so a would have to fit into c too.. (think of prime factorisation etc))
this means that we can optimise. If we sort the numbers smallest to largest and start with the smaller numbers first. First iteration, start with the smallest number as a
If we partition the numbers into two groups, group 1, the numbers which a divides, and group 2 the group which a doesn't divide, then we know that no numbers in group 1 can divide numbers in group 2 because no numbers in group 2 have a as a factor.
so if we had [2,3,4,5,6,7], we would start with 2 and get:
[2,4,6] and [3,5,7]
we can repeat the process on each group, splitting into smaller groups. This suggests an algorithm that could count the triples more efficiently. The groups will get really small really quickly, which means its efficiency should be fairly close to the size of the output.
This is the best answer that I was able to come up with so far. It's fast, but not quite fast enough. I'm still posting it because I'm probably going to abandon this question and don't want to leave out any progress I've made.
def answer(l):
num_dict = {}
ans_set = set()
for a2, a in enumerate(l):
num_dict[(a, a2)] = []
for x2, x in enumerate(l):
for y2, y in enumerate(l):
if (y, y2) != (x, x2) and y % x == 0:
pair = (y, y2)
num_dict[(x, x2)].append(pair)
for x in num_dict:
for y in num_dict[x]:
for z in num_dict[y]:
ans_set.add((x[0], y[0], z[0]))
return len(ans_set)
I'm having some trouble with the itertools.count function, and I don't quite understand what it does. I expect the code below to accomplish Project Euler problem 2.
I know that I could write this with a simple while loop, but is there a way to do it with a list comprehension? This code just freezes as I guess it's going to go infinity with count(). I would have hoped it would stop after x > MAX, but I know that won't happen. Is there a way to stop count in a generator expression like below?
def fib(n):
if (n <= 1): return 1
else: return fib(n-1) + fib(n-2)
MAX = 4000000
infiniteFib = (fib(x) for x in count())
s = (x for x in infiniteFib if x < MAX and x % 2 == 0)
print sum(s)
You could use takewhile:
>>> from itertools import count, takewhile, imap
>>> sum(x for x in takewhile(lambda x: x < 4000000, imap(fib, count())) if x % 2 == 0)
4613732
We just need to tell the infiniteFib generator when to stop yielding elements. itertools provides a number of useful methods to help with this:
less_than_max = itertools.takewhile(lambda x: x<MAX, infiniteFib))
even = itertools.ifilter(lambda x: x%2==0, less_than_max)
print sum(even)
We get a generator for all the numbers yielded by infiniteFib, until one returned is greater than MAX. Then we filter that generator, choosing only the even numbers. And finally we can sum the result.
How about:
def fib():
a, b = 1, 1
while True:
yield b
a, b = b, a+b
sum(f for f in itertools.takewhile(functools.partial(operator.ge, 4000000), fib()) if f % 2 == 0)
Or, pushing the parity check into the generator:
def even_fib():
a, b = 1, 1
while True:
if b % 2 == 0: yield b
a, b = b, a+b
sum(itertools.takewhile(functools.partial(operator.ge, 4000000), even_fib()))
Yeah, count() just keeps going, which isn't what you want. List comprehensions / iterator expressions don't have flexible exit conditions (but see #DSM's solution using takewhile).
I prefer just using while.
Here's my old answer to Euler 2:
def SumEvenFibonacci(limit):
x = y = 1
sum = 0
while (sum <= limit):
sum += (x + y)
x, y = x + 2 * y, 2 * x + 3 * y
return sum
ce = SumEvenFibonacci(4000000)
print ce
Here's another solution using takewhile, but non-recursively. Since the recursive solution requires calculating all the fibs less than n for each n, it's horrible slow.
def fib_gen(only_even=False):
one = 1
if not only_even:
yield one
two = 1
if not only_even:
yield two
while True:
next = one + two
one = two
two = next
if only_even:
if next % 2 == 0:
yield next
else:
yield next
list(itertools.takewhile(lambda x: x < 4000000, fib_gen()))