trouble with bubble in python - python

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.

Related

"+" vs append in list in python

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()

Is this an example of call-by-reference, a bug, or something else? [duplicate]

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)
...

Sorting for index values using a binary search function in python

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).

In this short recursive function `list_sum(aList)`, the finish condition is `if not aList: return 0`. I see no logic in why this condition works

I am learning the recursive functions. I completed an exercise, but in a different way than proposed.
"Write a recursive function which takes a list argument and returns the sum of its integers."
L = [0, 1, 2, 3, 4] # The sum of elements will be 10
My solution is:
def list_sum(aList):
count = len(aList)
if count == 0:
return 0
count -= 1
return aList[0] + list_sum(aList[1:])
The proposed solution is:
def proposed_sum(aList):
if not aList:
return 0
return aList[0] + proposed_sum(aList[1:])
My solution is very clear in how it works.
The proposed solution is shorter, but it is not clear for me why does the function work. How does if not aList even happen? I mean, how would the rest of the code fulfill a not aList, if not aList means it checks for True/False, but how is it True/False here?
I understand that return 0 causes the recursion to stop.
As a side note, executing without if not aList throws IndexError: list index out of range.
Also, timeit-1million says my function is slower. It takes 3.32 seconds while the proposed takes 2.26. Which means I gotta understand the proposed solution.
On the call of the function, aList will have no elements. Or in other words, the only element it has is null. A list is like a string or array. When you create a variable you reserve some space in the memory for it. Lists and such have a null on the very last position which marks the end so nothing can be stored after that point. You keep cutting the first element in the list, so the only thing left is the null. When you reach it you know you're done.
If you don't use that condition the function will try to take a number that doesn't exist, so it throws that error.
You are counting the items in the list, and the proposed one check if it's empty with if not aList this is equals to len(aList) == 0, so both of you use the same logic.
But, you're doing count -= 1, this has no sense since when you use recursion, you pass the list quiting one element, so here you lose some time.
According to PEP 8, this is the proper way:
• For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
Here is my amateur thougts about why:
This implicit check will be faster than calling len, since len is a function to get the length of a collection, it works by calling an object's __len__ method. This will find up there is no item to check __len__.
So both will find up there is no item there, but one does it directly.
not aList
return True if there is no elements in aList. That if statement in the solution covers edge case and checks if input parameter is not empty list.
For understand this function, let's run it step by step :
step 0 :
L=[0,1,2,3,4]
proposed_sum([0,1,2,3,4])
L != []
return l[0] + proposed_sum([1,2,3,4])
step 1 calcul proposed_sum([1,2,3,4]):
proposed_sum([1,2,3,4])
L != []
return l[0] + sum([2,3,4])
step 2 calcul proposed_sum([2,3,4]):
proposed_sum([2,3,4])
L != []
return l[0] + sum([3,4])
step 3 calcul proposed_sum([3,4]):
proposed_sum([3,4])
L != []
return l[0] + sum([4])
step 4 calcul proposed_sum([4]):
proposed_sum([4])
L != []
return l[0] + sum([])
step 5 calcul proposed_sum([]):
proposed_sum([])
L == []
return 0
step 6 replace:
proposed_sum([0,1,2,3,4])
By
proposed_sum([]) + proposed_sum([4]) + proposed_sum([3,4]) + proposed_sum([2,3,4]) + proposed_sum([1,2,3,4])+ proposed_sum([0,1,2,3,4])
=
(0) + 4 + 3 + 2 + 1 + 0
Python considers as False multiple values:
False (of course)
0
None
empty collections (dictionaries, lists, tuples)
empty strings ('', "", '''''', """""", r'', u"", etc...)
any other object whose __nonzero__ method returns False
in your case, the list is evaluated as a boolean. If it is empty, it is considered as False, else it is considered as True. This is just a shorter way to write if len(aList) == 0:
in addition, concerning your new question in the comments, consider the last line of your function:
return aList[0] + proposed_sum(aList[1:])
This line call a new "instance" of the function but with a subset of the original list (the original list minus the first element). At each recursion, the list passed in argument looses an element and after a certain amount of recursions, the passed list is empty.

Removing duplicates from a string in Python without using adittional buffer

I want to resolve this problem in Python:
given a string (without spacing), remove the duplicates without using an adittional buffer.
I have the following code:
def removedup(st):
temp = []
for i in range(len(st)):
if st[i] not in temp:
temp.append(st[i])
return temp
which returns a list without duplicates.
1-This code in O(n^2) right?
2- How I can do the same without using an additional buffer in python?? (I mean not using a list). Maybe I can use a string (not a list) but am not sure if this adds complexity. Also, strings in python are immutable, so I can't do some type of indexing to change something. (Like in C++ or Java).
What is the best way to resolve this in Python? I know that there is some questions that "looks like" duplicates here, but my question is more Python related (solving this without an additional buffer).
Thank you!
1) Yes.
2) Well
return set(st)
..is by far the simplest way to uniquify a string (or any iterable). I don't know if you consider this an "additional buffer" or not. Some extra memory needs to be allocated for another object any way you do it, since strings are immutable as you say.
This of course does not preserve order, and if that's an issue there's always the super-obvious:
from collections import OrderedDict
return ''.join(OrderedDict.fromkeys(st))
0) Apparently you have to use at least one additional buffer since, as you have mentioned, python strings are immutable and you need at least to return result somehow, right? So internaly at least one buffer is already used (even if you name it with the same name).
You can, of course, use string as buffer, they can do string + string or string += string, or even string[:n-1] + string[n:], but because of immutability, internaly it creates new object each time.
You can use some other, mutable, iterable instead of string, so it would work.
1) No, your code is not O(N**2). It's O(N*log(N)) in the worst case scenario (all symbols are unique) and O(N) in best case scenario (all symbols are just one symbol).
2) Assuming that you use list instead of string of string, you could do something like this:
def dup_remove(lst):
i = 0
n = len(lst)
while i < n:
if lst[i] in lst[:i]:
del lst[i]
n -= 1
else:
i += 1
return lst
it's still O(N*Log(N)) in worst case scenario, but it does not use any additional buffers which is what you wanted in the first place. I think that for practical purpose solution with OrderedDict should be more optimal though.
Another way to do it through list slicing loop.
# O(n ^ 2)
for item in input_list[:]:
index = input_list.index(item) + 1
while index < len(input_list):
if input_list[index] == item:
del input_list[index]
index += 1
Since slice creates a copy, if you truly want a solution without any internal buffers, this will do.
# O(n ^ 2)
i = 0
while i < len(input_list):
j = i + 1
while j < len(input_list):
if input_list[j] == input_list[i]:
del input_list[j]
# Don't increment j here since the next item
# after the deleted one will move to index j
else:
j += 1
i += 1
1) I'm not sure.
2) A very efficient way is coded below. Note that I don't use any additional package. I don't even use lists, just a string!
def removeDuplicate (input):
i = 0
while i < len(input)-1:
j = i + 1
while j < len(input):
if input[j] == input[i]:
input_list = input_list[0:j] + input_list[j+1:]
# Don't increment j here since the next item
# after the deleted one will move to index j
else:
j += 1
i += 1
return input

Categories