I need some help because I think I'm lost. I've search before in this site and of course I've Google it, but believe me that if it was so simple to me, I haven't ask it at all, so please be kind to me.
I'm new to python and coding isn't that easy to me.
Anyway, take a look at my code:
def coin_problem(price, cash_coins):
if (price < 0):
return []
if (price == 0):
return [[]]
options = []
for a_coin in cash_coins:
coins_minus_coin = cash_coins[:]
coins_minus_coin.remove(a_coin)
sub_coin_problem = coin_problem (price - a_coin, cash_coins)
for coin in sub_coin_problem:
coin.append(a_coin)
options.extend(sub_coin_problem)
return options
print coin_problem(4, [1, 2])
As you can see, I've tried to deal with the famous coin problem by recursion (and as I wrote before, I know many have already asked about this, I read their questions and the answers but I still couldn't understand the fully solutions).
This code was made by me, all of it. And now I'm stuck and confused. When the value of "price" is 4 and the value of "cash_coins" is [1,2] instead of returning something like this:
[1,1,1,1]
[2,2]
[2,1,1]
I get something more like:
[[1, 1, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 2]]
the combination of "2" and the double "1" repeats 3 times instead of "1".
I don't know what should I do in order to fix the problem or to improve my code so it will work better.
When you want to add a single item to a list, use append. When you want to combine two lists together, use extend.
Tips:
coins_minus_coin = cash_coins[:]
coins_minus_coin.remove(coin)
You never use this variable.
for i in sub_coins:
i.append(coin)
cash_coins_options.append(sub_coins)
You never use i either. I'd guess you meant:
for i in sub_coins:
i.append(coin)
cash_coins_options.append(i)
That solves the problem of stange results, but your solution will still only find []. Why? Your recursion can only stop on a return []; it can't handle another fundamental case when you can tell the price using a single coin. Try adding at the top this simple condition:
# actually I changed my mind-
# I assume you're learning so try this one yourself :-)
This will cause your function to behave much better:
>>> print coin_problem(4, [1,2])
[[2, 1, 1], [1, 2, 1], [2, 2]]
which manages to produce correct answers (even though it duplicates some of them).
Related
I am attempting to create the Just One board game, and I am having a hard time finding an efficient way to remove similar clues without having spaghetti code. The way the game works is that any submitted clues that are similar are removed from the clues list, which is what I am trying to replicate here. From what I can tell, it does seem to work with at least two clues that are the same (example bones, bone, and wishbone). Is there a more effective and less spaghetti-like way to write this?
for y in range(0,len(clues)):
if y == len(clues)-1:
break
for z in range(y+1,len(clues)):
if clues[y] in clues[z] or clues[z] in clues[y]:
first_word = str(clues[y])
second_word = str(clues[z])
try:
while True:
clues.remove(first_word)
except:
pass
try:
while True:
clues.remove(second_word)
except:
pass
I would usually turn the data from a list into a set. Sets usually only take 1 of the data, a set can't store the same data, so I think by turning your list into a set with the set() functions, it will erase all similar pieces of data.
Code:
clues = [1, 3, 5, 1, 2, 3]
print(clues)
clues = set(clues)
print(clues)
Output:
[1, 3, 5, 1, 2, 3]
{1, 2, 3, 5}
I am trying to code a recursive function that generates all the lists of numbers < N who's sum equal to N in python
This is the code I wrote :
def fn(v,n):
N=5
global vvi
v.append(n) ;
if(len(v)>N):
return
if(sum(v)>=5):
if(sum(v)==5): vvi.append(v)
else:
for i in range(n,N+1):
fn(v,i)
this is the output I get
vvi
Out[170]: [[1, 1, 1, 1, 1, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5]]
I tried same thing with c++ and it worked fine
What you need to do is to just formulate it as a recursive description and implement it. You want to prepend all singleton [j] to each of the lists with sum N-j, unless N-j=0 in which you also would include the singleton itself. Translated into python this would be
def glist(listsum, minelm=1):
for j in range(minelm, listsum+1):
if listsum-j > 0:
for l in glist(listsum-j, minelm=j):
yield [j]+l
else:
yield [j]
for l in glist(5):
print(l)
The solution contains a mechanism that will exclude permutated solutions by requiring the lists to be non-decreasing, this is done via the minelm argument that limits the values in the rest of the list. If you wan't to include permuted lists you could disable the minelm mechanism by replacing the recursion call to glist(listsum-j).
As for your code I don't really follow what you're trying to do. I'm sorry, but your code is not very clear (and that's not a bad thing only in python, it's actually more so in C).
First of all it's a bad idea to return the result from a function via a global variable, returning result is what return is for, but in python you have also yield that is nice if you want to return multiple elements as you go. For a recursive function it's even more horrible to return via a global variable (or even use it) since you are running many nested invocations of the function, but have only one global variable.
Also calling a function fn taking arguments v and n as argument. What do that actually tell you about the function and it's argument? At most that it's a function and probably that one of the argument should be a number. Not very useful if somebody (else) is to read and understand the code.
If you want an more elaborate answer what's formally wrong with your code you should probably include a minimal, complete, verifiable example including the expected output (and perhaps observed output).
You may want to reconsider the recursive solution and consider a dynamic programming approach:
def fn(N):
ways = {0:[[]]}
for n in range(1, N+1):
for i, x in enumerate(range(n, N+1)):
for v in ways[i]:
ways.setdefault(x, []).append(v+[n])
return ways[N]
>>> fn(5)
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 2], [1, 1, 3], [2, 3], [1, 4], [5]]
>>> fn(3)
[[1, 1, 1], [1, 2], [3]]
Using global variables and side effects on input parameters is generally consider bad practice and you should look to avoid.
I am new to programming and am having a problem with an algorithm I am writing in python. It first assembles a list from a sequence of variables (which each contain a list), and I need it to be able to call the same variable multiple times within a sequence. It then processes the list Like this:
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
def function(input):
return output
so that function(c) returns [[1, 2, 3, output_a1], [4,5,6, output_b1]]
If anyone would like to know more about the function, I will gladly provide more information, but my troubleshooting this far has led me to believe that the source problem is rather simple. The problem I am having is that if I call the same variable multiple times in my master list like so: c = [a, b, a], I would like function(c) to return:
[[1, 2, 3, output_a1],
[4, 5, 6, output_b1],
[1, 2, 3, output_a2]]
However, function() processes all instances of a when it encounters just one, so that I get:
[[1, 2, 3, output_a1, output_a3],
[4, 5, 6, output_b1],
[1, 2, 3, output_a1, output_a3]]
I have found two ways to fix this, but I am really not happy with them and I suspect there is a better way. In the first way, I print c and copy and paste it into the function:
function_a([[1, 2, 3], [4, 5, 6], [1, 2, 3]])
and this returns the desired output. Additionaly, I can create another variable with the same contents as a, d = [1, 2, 3], and have c = [a, b, d], and once again, function_a(c) will return the desired output. I have tried a variety of things, but it seems that if any element in c is linked to another through variables, then I encounter this error. Since I will be running this algorithm with fairly lengthy sequences that may contain several instances of the same element, I would really like a clean way to fix this error. Any advice is much appreciated, and I will provide more details about the function if need be. Thanks for reading!
In case anyone is reading this with the same problem, Roberto responded with this link which provided all the information I needed to solve the problem. Little did I know, if I am working with a nested list that contains multiple copies from the same variable, I need to make a deep copy of it to prevent any part of the list from being modified.
I recently started coding in Python 2.7. I'm a molecular biologist.
I'm writing a script that involves creating lists like this one:
mylist = [[0, 4, 6, 1], 102]
These lists are incremented by adding an item to mylist[0] and summing a value to mylist[1].
To do this, I use the code:
def addres(oldpep, res):
return [oldpep[0] + res[0], oldpep[1] + res[1]]
Which works well. Since mylist[0] can become a bit long, and I have millions of these lists to take care of, I thought that using append or extend might make my code faster, so I tried:
def addres(pep, res):
pep[0].extend(res[0])
pep[1] += res[1]
return pep
Which in my mind should give the same result. It does give the same result when I try it on an arbitrary list. But when I feed it to the million of lists, it gives me a very different result. So... what's the difference between the two? All the rest of the script is exactly the same.
Thank you!
Roberto
The difference is that the second version of addres modifies the list that you passed in as pep, where the first version returns a new one.
>>> mylist = [[0, 4, 6, 1], 102]
>>> list2 = [[3, 1, 2], 205]
>>> addres(mylist, list2)
[[0, 4, 6, 1, 3, 1, 2], 307]
>>> mylist
[[0, 4, 6, 1, 3, 1, 2], 307]
If you need to not modify the original lists, I don't think you're going to really going to get a faster Python implementation of addres than the first one you wrote. You might be able to deal with the modification, though, or come up with a somewhat different approach to speed up your code if that's the problem you're facing.
List are objects in python which are passed by reference.
a=list()
This doesn't mean that a is the list but a is pointing towards a list just created.
In first example, you are using list element and creating a new list, an another object while in the second one you are modifying the list content itself.
Started to learn programming 2 months ago, in one of my little projects i encountered the need to generate permutations of list of objects.
I knew that i'll find how to do this if i'll just searched for it, but i wanted to make one of my own, so i worked up and made my own permutation generator code:
def perm(lst, c = [], x = 0):
i = -1
g = len(lst) - 1
if x == g:
while i < g:
i += 1
if lst[i] in c:
continue
c.append(lst[i])
print(c)
del c[-1]
i = g
else:
while i < g:
if x == 0:
del c[:]
elif g == x:
del c[-1]
elif len(c) > x:
del c[-1]
continue
i += 1
if lst[i] in c:
continue
c.append(lst[i])
x + 1
perm(lst, c, x + 1)
This is what it gives if i run it:
perm(range(2))
[0, 1]
[1, 0]
perm([1, 4, 5])
[1, 4, 5]
[1, 5, 4]
[4, 1, 5]
[4, 5, 1]
[5, 1, 4]
[5, 4, 1]
It works as i expected, but when i use bigger lists it take some time for it to generate all the permutations of the list.
So all i want is hints on how to improve my code, only hints.
Or if you can tell me what should i learn to be able to make a better generator?
Thanks in advance for all the helpers.
Generating permutations is often done recursively. Given a list of 5 items, the permutations can be created by picking each of the 5 elements in turn as the first element of the answer, then for each of them permuting the remaining 4 elements, and appending them together.
>>> from itertools import permutations
>>> list(permutations(range(2)))
[(0, 1), (1, 0)]
>>> list(permutations([1, 4, 5]))
[(1, 4, 5), (1, 5, 4), (4, 1, 5), (4, 5, 1), (5, 1, 4), (5, 4, 1)]
In the docs there is Python code available for legacy versions.
A note re your code, x + 1 doesn't do anything as you're not assigning result of that expression to anyting.
The best way to understand what is making your code slow is to actually measure it. When you attempt to guess at what will make something fast, it's often wrong. You've got the right idea in that you're noticing that your code is slower and it's time for some improvement.
Since this is a fairly small piece of code, the timeit module will probably be useful. Break the code up into sections, and time them. A good rule of thumb is that it's better to look at an inner loop for improvements, since this will be executed the most times. In your example, this would be the loop inside the perm function.
It is also worth noting that while loops are generally slower than for loops in python, and that list comprehensions are faster than both of these.
Once you start writing longer scripts, you'll want to be aware of the ability to profile in python, which will help you identify where your code is slow. Hopefully this has given you a few places to look.
OK, for large lists, a recursive solution will take more and more time & space, and eventually reach the recursion limit and die. So, on the theoretical side, you could work on ways to save time and space.
Hint: tail-recursive functions (such as the one you've written) can be rewritten as loops
On a more practical side, you may consider the use cases of your function. Maybe there's somebody who doesn't want the whole list of permutations at once, but a single one each time - there's a good opportunity to learn about yield and generators.
Also, for something generally not directly applicable to your question: k-combinations and multisets are closely related to permutations. Perhaps you can extend your function (or write a new one) which will produce the k-combinations and/or multiset the user asks for.
The first thing I notice is that the code is hard to understand. The variable names are completely meaningless, replace them with meaningful names. It also seems like you're using i as a loop index, which is almost always bad style in python, because you can do for item in list:.
This is not really performance related, but there is a glaring bug in the code. Using a list as a default parameter does not do what you think it does - it will create one list object that will be shared by every call to perm(), so the second time you call perm you will have the value in c of whatever it contained when the last call finished. This is a common beginner's error.
You also say "when I use bigger lists it takes some time to generate all the permutations of the list". What did you expect? The number of permutations is equal to the factorial of the length of the list, and that grows big fast! For example a list of length 20 will have 2432902008176640000 permutations. Even the most efficient algorithm in the world is "going to take some time" for a list this size, even if it did not run out of memory first. If our hypothetical algorithm generated a billion permutations a second it would still take 77 years to run. Can you be more specific about the length of lists you are using and how long it is taking?