I'm new to Python3 and are trying to do a recursive powerset function. It should use list comprehension.
I wrote:
def powerset(seq):
if not seq:
return [[]]
return powerset(seq[1:]) + [[seq[0]] + n for n in powerset(seq[1:])]
This function works but I got feedback and was told it was unnecessary to call the function two times. It did to much computing. It should easily be able to compute up to 20 powersets. So how should I do? I can't get it to work without calling the function twice. Thanks.
Just calculate powerset(seq[1:]) once, store it in a variable, and use it twice:
def powerset(seq):
if not seq:
return [[]]
ps = powerset(seq[1:])
return ps + [[seq[0]] + n for n in ps]
The difference to yours is that this way, you use ps twice, but you compute it just once.
Alternatively, you could use a double list-comprehension (if you like that sort of thing...)
def powerset(seq):
return [x for ps in powerset(seq[1:]) for x in ([seq[0]] + ps, ps)] if seq else [[]]
Here, the same temporary variable ps is defined inside the list comprehension. Note, however, that the results will be in a slightly different order this way.
I feel very unclear. I actually don't understand how just assigning it to a variable can change that? It means the same thing?
You seem to think too much in terms of pure math here. In programming, y = f(x) does not mean "y is the same as/synonymous for f(x)", but "assign the result of f(x) to y".
Related
I am trying to implement an incrementation to a previously defined variable called sum.
return [sum = sum + number for number in range(a,b)]
Of course this format brings up error but using the similar:
return [sum = number for number in range(a,b)]
The code is faulty but runs. If there's a way to implement it and return sum the code would work.
And also if someone could inform me about the nomenclature I'd forever be grateful.
Here are a few possible answers. What you are using is called a list comprehension.
s += (b*(b-1) - a*(a-1))//2
s += sum([n for n in range(a,b)])
for n in range(a,b):
s += n
It's not a good idea to name a variable sum as it is a built in Python function.
Try the following:
return sum([number for number in range(a,b)])
As said in the commentaries, sum is a python built-in function which, given an array, it returns the result of the addtion of all elements in it
You essentially reimplemented the built-in function sum. Just call the function directly:
return sum(range(a, b))
I'm new in python and I wrote code to have the product of items in a list without using the multiplication sign:
def witOutmultiply(some_list):
first_num = some_list[0]
result = 0
for n in some_list[1:]:
for i in range(n):
result += first_num
first_num = result
result = 0
return first_num
q =[2,4,5,6,10,15]
print(witOutmultiply(q))
My question is: can I use comprehensions in this case, and can I get the result with just one loop? Thanks
Yes, you can use list comprehension, sum, and range, but no other builtin functions:
q = [2,4,5,6,10,15]
mult = q[0]
for n in q[1:]:
mult = sum(mult for _ in range(n))
print(mult)
#36000
Here is an answer with no loop at all that satisfies your condition of "no multiplication sign." It is therefore very fast. The reduce function repeats an operation between members of an iterable, reducing it to a single value, while the mul function multiplies two numbers. The 1 at the end of the reduce function gives a reasonable value if the iterable (list) is empty. No multiplication sign in sight!
from operator import mul
from functools import reduce
def prod_seq(seq):
"""Return the product of the numbers in an iterable."""
return reduce(mul, seq, 1)
Comprehensions are used to build data structures. A list comprehension builds a list, a dict comprehension builds a dict, etc. Since you want a single value rather than a data structure in your computation, there's no good reason to use a comprehension.
There probably are ways to avoid using two loops, but it's not going to be easy, since your outer loop does several operations, not just one. Most of the easy ways to avoid an explicit loop will just be hiding one or more loops in some function call like sum. I think that for your chosen algorithm (doing multiplication by adding), your current code is quite good and there's no obvious way to improve it.
from numpy import prod
print(prod(q))
#36000
I have a list comprehension which approximates to:
[f(x) for x in l if f(x)]
Where l is a list and f(x) is an expensive function which returns a list.
I want to avoid evaluating f(x) twice for every non-empty occurance of f(x). Is there some way to save its output within the list comprehension?
I could remove the final condition, generate the whole list and then prune it, but that seems wasteful.
Edit:
Two basic approaches have been suggested:
An inner generator comprehension:
[y for y in (f(x) for x in l) if y]
or memoization.
I think the inner generator comprehension is elegant for the problem as stated. In actual fact I simplified the question to make it clear, I really want:
[g(x, f(x)) for x in l if f(x)]
For this more complicated situation, I think memoization produces a cleaner end result.
[y for y in (f(x) for x in l) if y]
Will do.
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), it's possible to use a local variable within a list comprehension in order to avoid calling twice the same function:
In our case, we can name the evaluation of f(x) as a variable y while using the result of the expression to filter the list but also as the mapped value:
[y for x in l if (y := f(x))]
A solution (the best if you have repeated value of x) would be to memoize the function f, i.e. to create a wrapper function that saves the argument by which the function is called and save it, than return it if the same value is asked.
a really simple implementation is the following:
storage = {}
def memoized(value):
if value not in storage:
storage[value] = f(value)
return storage[value]
[memoized(x) for x in l if memoized(x)]
and then use this function in the list comprehension. This approach is valid under two condition, one theoretical and one practical. The first one is that the function f should be deterministic, i.e. returns the same results given the same input, and the other is that the object x can be used as a dictionary keys. If the first one is not valid than you should recompute f each timeby definition, while if the second one fails it is possible to use some slightly more robust approaches.
You can find a lot of implementation of memoization around the net, and I think that the new versions of python have something included in them too.
On a side note, never use the small L as a variable name, is a bad habit as it can be confused with an i or a 1 on some terminals.
EDIT:
as commented, a possible solution using generators comprehension (to avoid creating useless duplicate temporaries) would be this expression:
[g(x, fx) for x, fx in ((x,f(x)) for x in l) if fx]
You need to weight your choice given the computational cost of f, the number of duplication in the original list and memory at you disposition. Memoization make a space-speed tradeoff, meaning that it keep tracks of each result saving it, so if you have huge lists it can became costly on the memory occupation front.
You should use a memoize decorator. Here is an interesting link.
Using memoization from the link and your 'code':
def memoize(f):
""" Memoization decorator for functions taking one or more arguments. """
class memodict(dict):
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
#memoize
def f(x):
# your code
[f(x) for x in l if f(x)]
[y for y in [f(x) for x in l] if y]
For your updated problem, this might be useful:
[g(x,y) for x in l for y in [f(x)] if y]
Nope. There's no (clean) way to do this. There's nothing wrong with a good-old-fashioned loop:
output = []
for x in l:
result = f(x)
if result:
output.append(result)
If you find that hard to read, you can always wrap it in a function.
As the previous answers have shown, you can use a double comprehension or use memoization. For reasonably-sized problems it's a matter of taste (and I agree that memoization looks cleaner, since it hides the optimization). But if you're examining a very large list, there's a huge difference: Memoization will store every single value you've calculated, and can quickly blow out your memory. A double comprehension with a generator (round parens, not square brackets) only stores what you want to keep.
To come to your actual problem:
[g(x, f(x)) for x in series if f(x)]
To calculate the final value you need both x and f(x). No problem, pass them both like this:
[g(x, y) for (x, y) in ( (x, f(x)) for x in series ) if y ]
Again: this should be using a generator (round parens), not a list comprehension (square brackets). Otherwise you will build the whole list before you start filtering the results. This is the list comprehension version:
[g(x, y) for (x, y) in [ (x, f(x)) for x in series ] if y ] # DO NOT USE THIS
There have been a lot of answers regarding memoizing. The Python 3 standard library now has a lru_cache, which is a Last Recently Used Cache. So you can:
from functools import lru_cache
#lru_cache()
def f(x):
# function body here
This way your function will only be called once. You can also specify the size of the lru_cache, by default this is 128. The problem with the memoize decorators shown above is that the size of the lists can grow well out of hand.
You can use memoization. It is a technique which is used in order to avoid doing the same computation twice by saving somewhere the result for each calculated value.
I saw that there is already an answer that uses memoization, but I would like to propose a generic implementation, using python decorators:
def memoize(func):
def wrapper(*args):
if args in wrapper.d:
return wrapper.d[args]
ret_val = func(*args)
wrapper.d[args] = ret_val
return ret_val
wrapper.d = {}
return wrapper
#memoize
def f(x):
...
Now f is a memoized version of itself.
With this implementation you can memoize any function using the #memoize decorator.
Use map() !!
comp = [x for x in map(f, l) if x]
f is the function f(X), l is the list
map() will return the result of f(x) for each x in the list.
Here is my solution:
filter(None, [f(x) for x in l])
How about defining:
def truths(L):
"""Return the elements of L that test true"""
return [x for x in L if x]
So that, for example
> [wife.children for wife in henry8.wives]
[[Mary1], [Elizabeth1], [Edward6], [], [], []]
> truths(wife.children for wife in henry8.wives)
[[Mary1], [Elizabeth1], [Edward6]]
Full disclosure: this is for an assignment. Simply getting working code is enough, but doing this in three lines gets me extra credit.
I'm trying to take a 1000-digit string and find the largest product of 5 consecutive digits. You may recognize this as Project Euler's Problem #8.
I've tried a lot of options, but I seem to be stuck. I'm working on figuring out if I can make a lambda statement that will work, but I have no experience with lambda so it's evading me.
Here's what I have so far:
for i in range(1, 996):
max = int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) if max < int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) else max = max
return max
That doesn't work and triggers SyntaxError: can't assign to conditional expression.
I don't want outright code, or at least not a complete function, but just a little help understanding how I can move forward.
This isn't legal python:
x = y if z else x = w
This is:
x = y if z else w
So is this:
if z: x = y
By the way, there is a one line solution, that is much shorter and clearer than your three.
= appears twice in your (very long) line. Effectively you have this:
max = something if something else max = max
which Python parses as:
max = (something if something else max) = max
And, indeed, you can't assign to a conditional expression, which is that whole thing in the middle.
You probably didn't intend to have the final = max at the end.
In [15]: def myinput(l,n):
...: for x in l:
...: yield l[x:x+n]
...:
In [16]: max([reduce(lambda a,b:a*b, x) for x in myinput(range(1000),5) if len(x)==5])
Out[16]: 985084775273880L
Like recursive mentioned, there is a simple one-liner solution. It involves using the max function - always bad to name variables after builtins!
In Python 2 it looks something like this:
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in xrange(996))
In Python 3 reduce was removed, so you have to get it through functools:
from functools import reduce
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in range(996))
Look into:
the built-in max function to find the greatest number in a sequence,
the built-in map function to apply a function to all elements in a list,
the built-in reduce function to obtain a single object as a result of applying a function that returns a single object repeatedly to two elements in a list,
lambda definitions to be able to define function objects that you can pass to map() and reduce(),
and list comprehensions (and generators, which are very similar) to compose the above functions in a one-liner.
I have a structure with an x amount of lists in lists, and each list an x amount of tuples. I don't know beforehand how many nested lists there are, or how many tuples in each list.
I want to make dictionaries out of all the tuples and because I don't know the depth of the lists I want to use recursion. What I did was
def tupleToDict(listOfList, dictList):
itemDict = getItems(list) # a function that makes a dictionary out of all the tuples in list
dictList.append(itemDict)
for nestedList in listOfList:
getAllNestedItems(nestedList, dictList)
return dictList
this works, but I end up with a huge list at the end. I would rather return the itemDict at every round of recursion. However, I don't know how to (if it is possible) return a value without stopping the recursion.
You're looking for yield:
def tupleToDict(listOfList):
yield getItems(listofList)
for nestedList in listOfList:
for el in getAllNestedItems(nestedList):
yield el
In Python 3.3+, you can replace the last two lines with a yield from.
You may want to rewrite your function to be iterative:
def tupleToDict(listOfList):
q = [listOfList]
while q:
l = q.pop()
yield getItems(l)
for nestedList in listOfList:
q += getAllNestedItems(nestedList)
Who are you going to return it to? I mean if your thread is busy running the recursive algorithm, who gets the "interim results" to process?
Best bet is to tweak your algorithm to include some processing before it recurses again.
I'm not sure what you're trying to do, but you could try to make a recursive generator by using the yield statement to return the dict at the desired intervals. Either that or shove copies of it into a global list?
You got two possible solutions:
The generator approach: a function with a yield statement, which may be a hassle to implement in a recursive function. (Look at phihags proposal for an example)
The callback approach: You call a helper-function/method from inside the recursion and can monitor the progress through a second outer function.
Here a non-recursive recursion example: ;-)
def callback(data):
print "from the depths of recursion: {0}".format(data)
def recursion(arg, callbackfunc):
arg += 1
callbackfunc(arg)
if arg <10:
recursion(arg, callbackfunc)
return arg
print recursion(1, callback)