Understading a quicksort python implementation - python

I found this code online.
def quick_sort(items):
""" Implementation of quick sort """
if len(items) > 1:
pivot_index = len(items) / 2
smaller_items = []
larger_items = []
for i, val in enumerate(items):
if i != pivot_index:
if val < items[pivot_index]:
smaller_items.append(val)
else:
larger_items.append(val)
quick_sort(smaller_items)
quick_sort(larger_items)
items[:] = smaller_items + [items[pivot_index]] + larger_items
The one line that gives me trouble is the last one. I believe it's basic concatenation, however, when I change "items[:]" to "items", the algorithm fails. What is special about the [:] at the end of the list?
If anyone one can help, I would really appreciate. Thank you in advance!

This is in-place assignment, without replacing the list object with a new object.
This way, the output is placed in the original list and can be read by the caller.

Related

Why swapping does not occur in below python code

def rev(n):
for i in range(int(len(n)//2)):
temp = n[i]
n[i] = n[len(n)-i-1]
n[len(n)-i-1] = temp
or,n[i], n[len(n)-i-1] = n[len(n)-i-1], n[i]
return n
n=[34,45,56,67]
print(rev(n))
Above code doesn't reverse the list even the logic is correct still the output is same as input.
Can anyone help me with that as i am little bit confused.
The intention appears to be to reverse the contents of a list in situ.
The most common way to do this is to create a new list with:
mylist[::-1]
...then... copy over the original like this:
mylist[:] = mylist[::-1]
However, the intent appears to be to use a custom loop to reverse in place.
def rev(_list):
i, j = 0, len(_list)
while (j := j - 1) > i:
_list[i], _list[j] = _list[j], _list[i]
i += 1
return _list
This demonstrates the correct element swap syntax and also obviates the need to create a new list. It is however very slow in comparison to traditional techniques

why does append not append the parameter

I was doing a bit of Leetcode and do not understand why res.append(subset) does not append the subset to res.
Could somebody explain the reason behind this?
def solve(arr):
res = []
def dfs(arr,subset):
if len(arr) == 0:
# why does the following line not append the subset to res?
res.append(subset)
for i in range(len(arr)):
subset.append(arr[i])
dfs(arr[:i] + arr[i+1:],subset)
subset.pop()
dfs(arr,[])
return res
Your problem is that you have assumed that res.append(subset) will append the items in subset. Python assignments for compound objects behave differently and so appending a list to a list is not the same as appending the values of a list to a list.
In this example, subset.pop() is removing values from subset and hence res, so that finally solve returns a list of empty lists. To make minimal changes to your code, I suggest that you copy the data using copy.deepcopy().
import copy
def solve(arr):
res = []
def dfs(arr,subset):
if len(arr) == 0:
# copy, rather than reference
res.append(copy.deepcopy(subset))
for i in range(len(arr)):
subset.append(arr[i])
dfs(arr[:i] + arr[i+1:],subset)
subset.pop()
dfs(arr,[])
return res
More information is available in the docs and there are simple examples in previous SO answers

python build a list recursively

Let's say I have a string
S = "qwertyu"
And I want to build a list using recursion so the list looks like
L = [u, y, t, r, e, w, q]
I tried to write code like this:
def rec (S):
if len(S) > 0:
return [S[-1]].append(rec(S[0:-1]))
Ideally I want to append the last element of a shrinking string until it reaches 0
but all I got as an output is None
I know I'm not doing it right, and I have absolutely no idea what to return when the length of S reaches 0, please show me how I can make this work
(sorry the answer has to use recursion, otherwise it won't bother me)
Thank you very much!!!
There are many simpler ways than using recursion, but here's one recursive way to do it:
def rec (S):
if not S:
return []
else:
temp = list(S[-1])
temp.extend(rec(S[:-1]))
return temp
EDIT:
Notice that the base case ensures that function also works with an empty string. I had to use temp, because you cannot return list(S[-1]).extend(rec(S[:-1])) due to it being a NoneType (it's a method call rather than an object). For the same reason you cannot assign to a variable (hence the two separate lines with temp). A workaround would be to use + to concatenate the two lists, like suggested in Aryerez's answer (however, I'd suggest against his advice to try to impress people with convoluted one liners):
def rec (S):
if not S:
return []
else:
return list(S[-1]) + rec(S[:-1])
In fact using + could be more efficient (although the improvement would most likely be negligible), see answers to this SO question for more details.
This is the simplest solution:
def rec(S):
if len(S) == 1:
return S
return S[-1] + rec(S[:-1])
Or in one-line, if you really want to impress someone :)
def rec(S):
return S if len(S) == 1 else S[-1] + rec(S[:-1])
Since append mutates the list, this is a bit difficult to express recursively. One way you could do this is by using a separate inner function that passes on the current L to the next recursive call.
def rec(S):
def go(S, L):
if len(S) > 0:
L.append(S[-1])
return go(S[0:-1], L)
else:
return L
return go(S, [])
L = [i for i in S[::-1]]
It should work.

My recursive insertion sort program is not working properly

Hello guys I am trying to implement insertion recursively but my list is not getting sorted. Any help or improvements are welcome.
sequence = [1,4,3,5,7,6,8,2]
def insertion(seq):
for i in range(len(seq)):
key = seq[i]
j = i
print(seq)
while j > 0 and seq[j-1] > key:
j = j - 1
seq[j] == key
insertion(sequence)
You have several errors in your code:
Your indentation is incorrect, fix that first.
You're missing a statement that should come as the first in the body
of the while loop to assign seq[j] to be the element that follows
it.
The seq[j] == key statement is a no-op -- this is not a ==
situation but rather a = one.
Your implementation isn't recursive, so once you get this code working, start over.

Logical Bug in the Code Related to Slicing in Python

Consider the following piece of code that generates all subsets of size k of an array [1,2,3,...,n]:
def combinations(n, k):
result = []
directed_combinations(n, k, 1, [], result)
return result
def directed_combinations(n, k, offset, partial_combination, result):
if len(partial_combination) == k:
new_partial = [x for x in partial_combination]
result.append(new_partial)
return
num_remaining = k - len(partial_combination)
i = offset
# kind of checks if expected num remaining is no greater than actual num remaining
while i <= n and num_remaining <= n - i + 1:
partial_combination.append(i)
directed_combinations(n, k, i + 1, partial_combination, result)
del partial_combination[-1]
# partial_combination = partial_combination[:-1] <-- same funcationality as line above, but produces weird bug.
i += 1
print(combinations(n=4,k=2))
For example, combinations(n=4,k=2) will generate all subsets of length 2 of [1,2,3,4].
There are two lines in the code that produce a list with the last element removed. I tried accomplishing it with del and creating a brand new list by slicing off the last element (i.e. [-1]). The version with del produces the correct result. But, version with [-1] doesn't. There is no runtime error; just a logical bug (i.e. incorrect result).
I suspect this has something to do with creating a new list when doing slicing vs. keeping the same list with del. I can't seem to understand why this is an issue.
I didn't notice at first that your function is recursive (should've read your tags better).
You're right, functionally the two are almost the same. Here is the exact same thing:
# del partial_combination[-1] # working (mutate)
# partial_combination = partial_combination[:-1] # different (rebind)
partial_combination[:] = partial_combination[:-1] # same (mutate)
The result of each of the above will be that you end up with a list containing the same elements. But while del and partial_combination[:] mutate your original list, the middle one rebinds the name to a new list with the same elements. When you pass on this new list to the next recursive step, it will operate on its own copy rather than on the single list the previous recursive levels are working on.
To prove this, you can call print(id(partial_combination)) after each of the above options, and see that the id changes in the rebinding case, while it stays the same throughout the mutating ones.

Categories

Resources