I am trying to implement bestSum algorithm in python and I have the following script with the issue at line 13,14.
memo = {}
def bestSum(s, l):
if s == 0:
return []
elif s < 0:
return None
elif s in memo:
return memo[s]
minList = None
for i in l:
temp = bestSum(s-i, l)
if temp != None:
temp = temp + [i] #This works LINE13
# temp.append(i) This does not work LINE14
if minList == None or len(temp) < len(minList):
minList = temp
memo[s] = minList
return minList
I know that "+" operator return a new list while the append function mutates the original list.
My question is why does it matter in my code as the temp list is only being used in the next few lines. Why are they giving different outputs.
The problem is not about a difference between append(i) and + [i], it's about how objects work in python. You got close to nailing it down.
First off, minilist = temp makes minilist refer to the same list object temp refers to, so appending to temp also appends to minilist. Meanwhile temp = temp + [i] makes temp a new reference to a new object, while minilist keeps the reference to the original list.
You can see that this is the reason by, for example, in the LINE13 version converting it to += [i], this makes temp keep it's reference thus it would alter both lists. In the LINE14 version you can add temp = temp.copy() before the append to make it a new object.
The difference is that the "+" operation acts specifically when you add an array by concatenating the element. The "append" method appends the object on the right-hand side that you give it, instead of taking the elements.
The + operator is used when you add a list by concatenating the element. The append method, append the item on the right side that you give it, instead of taking its elements, if you want to have a result similar to the + operator try to use extend()
Related
I am restrict myself to mutate a list using recursion only, I have a few small troubles when doing so.
def expand_strings(L,s,i):
if len(L) == 0:
return
else:
if len(L[0]) - 1 <= i:
L[0] += s
elif len(L[0]) - 1 > i:
new_string = L[0][:i] + s + L[0][i:]
L[0] = new_string
expand_strings(L[1:], s, i)
return
L: The input list containing possible 1 or more strings
s: The extra portion of string that I need to "insert" or "append" to the string elements within the list
i: The index of string where I want to insert or append s to.
The main goal of this function is the following:
1. if the index i within the range 0 ~ len(string_element_in_list), then I insert my s starting from index i
2. if the index i is larger than what the current string length, then I do the append s.
The problems I am having right now is that: I notice the recursion will only mutate the first element within the input list, and every element after the first element, they won't be affected by the mutation, I figure it might have something to do with the new input list I pass to the recursion, but I don't know precisely why this doesn't work.
Thanks for helping in advance. :)
The problem is in the recursive call expand_strings(L[1:], s, i). When you use slicing to get a part of your list, python creates a whole new copy of that sublist. So the recursive call creates a copy of your list, except the first element, and works on that copy.
One way of solving this problem can be returning the modified list from your method:
def expand_strings(L,s,i):
if len(L) == 0:
return []
else:
if len(L[0]) - 1 <= i:
L[0] += s
elif len(L[0]) - 1 > i:
new_string = L[0][:i] + s + L[0][i:]
L[0] = new_string
return [L[0]] + expand_strings(L[1:], s, i)
If you don't want to create a copy of the sublist every time (and return the modified list), you can add one more parameter to your method that would specify the location of the first element to modify. The base case would be where the starting index is equal to the length of the list.
def expand_strings(L,s,i,start):
if start == len(L):
return
if len(L[start]) - 1 <= i:
L[start] += s
else:
L[start] = L[start][:i] + s + L[start][i:]
expand_strings(L, s, i, start + 1)
This question already has answers here:
Are Python variables pointers? Or else, what are they?
(9 answers)
Closed 3 years ago.
I am writing a little program to create a list of permutations. I read about the algorithm on wikipedia.
My algorithm basically takes an initially sorted list of numbers, and permutes it in place. It then appends this new permutation to a list. When all permutations are found, it returns the list of lists containing all the permutations. It is very good at printing out the expected results, but when I try to add those results to a list, things get a little funny.
I noticed that every time I find the next permutation and append it to, the previous list elements get updated to the new permutation. So, at the end of it all, what gets returned is a list containing a bunch of copies of the same permutation (exactly the last permutation).
I've read that Python is pass by value, pass by reference and I've also read that it's neither. I'm not smart enough to argue with any of those people, but I am wondering why my program is doing this, and how to remedy it:
def lexi_order(nums):
permutations = []
length = len(nums)
while True:
# find largest index i such that nums[i] < nums[i + 1]
exists = False
for j, elem in enumerate(nums):
# check if last element
if j == length - 1:
break
if elem < nums[j + 1]:
i = j
exists = True
if not exists:
break
# find largest index k, such that i < k AND nums[i] < nums[k]
for j in range(i + 1, length):
if nums[j] > nums[i]:
k = j
# swap order of nums[i] and nums[k]
nums[i], nums[k] = nums[k], nums[i]
# reverse order of elements starting at position i+1
to_reverse = nums[i+1:][::-1]
nums[i+1::] = to_reverse
permutations.append(nums)
print(permutations)
return permutations
You're modifying the input (nums) in place each iteration through the loop, and then you keep adding a reference to the input to permutations. To fix it, make a copy of nums at the beginning of the loop and use it instead of the original everywhere inside it.
When you append nums to permutations, you are appending a reference to it, not copying all of the data over. When you modify nums, it gets modified everywhere. Python is pass by reference. If you make a change to a variable (not to be confused with reassigning it), that change will be reflected everywhere.
You need to make a copy of the passed nums, otherwise you are working on the passed reference. E.g.
def lexi_order(nums):
permutations = []
nums = list(nums) # We are now working on a copy, and won't mutate the original whatsoever.
length = len(nums)
...
I am trying to code the String permutation problem. Instead of string I have a list of integers like [1,2,3]. I have to print out all possible permutations of the list. However, there's some issue with my code that I'm not able to figure out. Somehow, the line if not in words in the base case hits only once. I'm trying to figure this out from the past one hour. Any help would be appreciated!. TIA
Here's the code
words = list()
def permute(nums):
if len(nums) == 0:
return None
l = 0
r = len(nums)
permute_helper(nums,0,r)
def permute_helper(nums,start,end):
current = 0
if start == end-1:
if not nums in words:
print 'appended'
words.append(nums)
else:
for current in range(start,end):
temp = nums[start]
nums[start] = nums[current]
nums[current] = temp
#Recursive call
permute_helper(nums,start+1,end)
temp = nums[start]
nums[start] = nums[current]
nums[current] = temp
permute([1,2,3])
print words
The bug is that you keep modifying the same list nums so you end up with only one copy that was modified but the modifications were not recorded.
Change:
words.append(nums)
to:
words.append(nums[:])
which will create a copy of nums and "freeze" it current state.
Comment:
You can do the swap in a more pythonic way, instead of:
temp = nums[start]
nums[start] = nums[current]
nums[current] = temp
do:
nums[start], nums[current] = nums[current], nums[start]
You're appending the same list each time. No wonder it's already there (in words).
In other words, you are not collecting each different permutation, but a reference to nums. So, subsequent permutations are reflected in words. That's the plague of mutability.
One solution is to make a copy of the current permutation:
words.append(nums[:])
By the way, a pythonic swap is:
a, b = b, a # no need for tmp
Also, there is no need to reset current.
I am being tasked with designing a python function that returns the index of a given item inside a given list. It is called binary_sort(l, item) where l is a list(unsorted or sorted), and item is the item you're looking for the index of.
Here's what I have so far, but it can only handle sorted lists
def binary_search(l, item, issorted=False):
templist = list(l)
templist.sort()
if l == templist:
issorted = True
i = 0
j = len(l)-1
if item in l:
while i != j + 1:
m = (i + j)//2
if l[m] < item:
i = m + 1
else:
j = m - 1
if 0 <= i < len(l) and l[i] == item:
return(i)
else:
return(None)
How can I modify this so it will return the index of a value in an unsorted list if it is given an unsorted list and a value as parameters?
Binary Search (you probably misnamed it - the algorithm above is not called "Binary Sort") - requires ordered sequences to work.
It simply can't work on an unordered sequence, since is the ordering that allows it to throw away at least half of the items in each search step.
On the other hand, since you are allowed to use the list.sorted method, that seems to be the way to go: calling l.sort() will sort your target list before starting the search operations, and the algorithm will work.
In a side note, avoid in a program to call anything just l - it maybe a nice name for a list for someone with a background in Mathematics and used to do things on paper - but on the screen, l is hard to disinguish from 1 and makes for poor source code reading. Good names for this case could be sequence lst, or data. (list should be avoided as well, since it would override the Python built-in with the same name).
I'm writing in python and I thought I might try to use recursion to create a bubble sort. My idea is that, since the rightmost element is always sorted after every iteration (list[-1]), I add that element to another call of bubblesort for the rest of my elements (bubbleSort(list[:-1])). Here is my code:
def bubbleSort(list):
sorted = True
i = 0
if len(list) <= 1:
return list
while i < len(list) - 1:
if list[i] > list[i+1]:
temp = list[i+1]
list[i+1] = list[i]
list[i] = temp
sorted = False
i = i + 1
if sorted:
return list
else:
endElement = list[-1]
return bubbleSort(list[:-1]) + [endElement]
However, it only ever returns the first iteration of the sort, despite it running through every iteration (I used print inside of the code to see if it was running). The recursion is necessary: I know how to do it without it. It's just the recursion part that messes up anyways.
Your intuition is correct. In fact, your code works for me (once the method contents are indented): http://codepad.org/ILCH1k2z
Depending on your particular installation of Python, you may be running into issues due to your variable name. In Python, list is a reserved word (it is the constructor for lists). In general, it is not considered good form to use a reserved word as a variable name. Try renaming your variable and see if your code runs correctly.
python programs are structured by indentation, not by parenthesis like c-like languages. i think this is the problem with your code.
try to indent it like this
#!/usr/env/python
def bubble(lst):
sorted = True
for i in range(len(lst) - 1):
if lst[i] > lst[i + 1]:
temp = lst[i]
lst[i] = lst[i + 1]
lst[i + 1] = temp
sorted = False
if sorted:
return lst
else:
return bubble(lst[:-1]) + [lst[-1]]
also you shouldn't use reserved words like list for variable names.
the test if the list has 1 or less elements is also unnecessary, because it wouldn't enter the loop.