I have a code of quicksort and counting comparisons that is working perfectly. But each time I call the function, the count keeps adding up again and again. Is there any way to avoid this?
count = 0
def quicksort(A, left = None, right =None):
global count
if left is None:
left = 0
if right is None:
right = len(A)
if left >= right:
return
p =A[left]
i = left +1
for j in range(left+1,right):
if A[j] < p:
A[i] , A[j] = A[j], A[i]
i = i + 1
A[left] , A[i-1] = A[i-1], A[left]
quicksort(A,left,i-1)
count += i-1-left
quicksort(A,i,right)
count += right-i-1
return A,count+len(A)
In order to make it work with a global count, you need to reset it at the first level of recursion. One way to do this is to move your implementation to a separate function _quicksort calling itself recursively, and reset the counter before the call:
def quicksort(A):
global count
count = 0
return _quicksort(A)
def _quicksort(A, left=None, right=None):
global count
...
_quicksort(A,left,i-1)
...
In addition, this simplifies your main function signature as the quicksort end user does not really need to know about left and right.
Now, it is better not to use a global variable at all as it is a bad practice. Then, you need to somehow pass a context to the _quicksort function for it to know which counter to deal with. So you would need to pass something as a parameter:
def _quicksort(context, A, left=None, right=None):
...
_quicksort(context, ...)
For example, this context could be a dictionary like {'count': 0} which you can then access as context['count'], or it could be an object to use context.count. Note that in this case this is getting really close to classes, where the context is the object itself and _quicksort would be a class method:
class _Quicksort(object):
count = 0
def _quicksort(self, A, left=None, right=None):
...
self._quicksort(A, ...)
self.count += ...
Finally, another common way to deal with the context in recursive functions is to pass and return variables "by value" such as:
def _quicksort(count, other_context, A, left=None, right=None):
...
count1, other_context1 = _quicksort(count, other_context, A, left, right)
...
return count + count1, other_context
But then you would end up with a cluttered method signature and would have to figure out what count means in this case and how to get the same result (which is a good exercise!).
Related
I have the following code:
class MyClass:
def __init__(self):
self.some_variable = None
def func1(self):
i = 1
while i < 10:
yield i * i
self.some_variable = len(str((i * i)))
i += 1
def func2(self):
*_, last = my_class.func1()
print(self.some_variable)
my_class = MyClass()
my_class.func2()
As you can see, some_variable is the length of the last element in the generator. Basically, I was wondering, is this the most pythonic way of getting this variable? If not, how should this be done? I'm just wondering if this is how it should be done or if there's a better way of doing this.
Probably the simplest code is to simply use a for loop to consume the generator, doing nothing in the loop body. The loop variable will have the last value from the generator after the loop ends, which is exactly what you want.
for x in some_generator():
pass
print(x) # print the last value yielded by the generator
This may be a little more efficient than other options because it discards all the values before the last one, rather than storing them in a list or some other data structure.
I think that one pythonic way would be to yield both the element and the length:
def func1():
i = 1
while i < 10:
yield i * i, len(str((i * i)))
i += 1
def func2():
*_, (_, last_len) = func1()
print(last_len)
func2()
or even to extract the calculation of the derived value to another function and call it after consuming the generator:
def func1():
i = 1
while i < 10:
yield i * i
i += 1
def func2(i):
return len(str(i))
def func3():
*_, last = func1()
print(func2(last))
func3()
I think that you have simplified your example too much to be able to find the solution that fits your real use case the best.
I found a solution to Leetcode NO. 543 Diameter of Binary Tree which is solved with the use of global variables. I have the solution shown in the text below. The author used a scalar variable, 'self.res', to store the final answer which is updated when the program traverses through the given binary tree.
I am wondering why the author needs to use self.res rather than a generic integer variable---for example, res only---to store the answer; when I replace self.res with res, the answer is wrong. Can anyone point out the difference?
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.res = 0
def depth(root):
if not root:
return 0
left = depth(root.left)
right = depth(root.right)
self.res = max(self.res, left + right)
return max(left, right) + 1
depth(root)
return self.res
Strictly speaking, it doesn't have to be an attribute. It could be a non-local variable.
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
res = 0
def depth(root):
nonlocal res
if not root:
return 0
left = depth(root.left)
right = depth(root.right)
res = max(res, left + right) # the key to memorize the result
return max(left, right) + 1
depth(root)
return res
Without the nonlocal statement, res would be a local variable that isn't set the first time depth tries to use it in the call to max.
Python 2 did not have a nonlocal statement, so an instance attribute would have been the best alternative to a global variable for persisting state between calls to depth. (The type hints indicate this probably wasn't written for Python 2, but old habits can die hard.) In Python 3, using nonlocal, the above no longer even uses self, so diameterOfBinaryTree can trivially be written as a regular function rather than an instance method of an unnecessary class.
I have the following class:
class Node():
def __init__(self, symbol, rule, children):
self.symbol = symbol
self.rule = rule
self.children = children
def addChild(self,child):
self.children.append(child)
I use it to build parsing trees; now I'm trying to use this function:
def simplify(n):
if len(n.children) == 0:
return n
if len(n.children) > 1:
for c in n.children:
c = simplify(c)
return n
while len(n.children) == 1:
print n.symbol,
n = n.children[0] #What is wrong here?
print n.symbol
return n
to simplify trees by removing internal nodes that have just one child. For instance:
S S
/ \ should become / \
E X v X
/
v
When I run the code, the two print statements show me that n was correctly replaced by n.children[0] , but when the tree is printed (right after this funtion is used), I see the same one. What's the problem here?
In your simplify() function, the parameter n is a reference to some specific node, and you can change what node it refers to; but reassigning n doesn't change any of the other structure. As a specific example, this loop actually does nothing:
for c in n.children:
# simplify has no side effects and leaves the input structure unchanged
c = simplify(c)
# c is never used again so the simplified result is lost
There's two reasonable approaches to solving this. One is to construct a new tree as the result of simplify:
def simplify(n):
if len(n.children) > 1:
new_children = [simplify(c) for c in n.children]
return Node(n.symbol, n.rule, new_children)
# and other cases
This has the advantage that your data structure is immutable: if you have two references to the tree hanging around, you know that rewriting one isn't going to destroy the other; if you have a reference to a node in the middle of the tree, there's no risk of it unexpectedly becoming "orphaned".
Still, it is common enough to see mutable data structures, and you could add your simplify method into the Node class to rewrite a node in place:
class Node:
def simplify(self):
if len(self.children) == 1:
return self.children[0].simplify()
if len(self.children) > 1:
self.children = [c.simplify() for c in self.children]
return self
Suppose I convert the below pseudocode to Python. Regarding specifically the parameter indicated as 1st half of A, does Python have a mechanism like A[1..n/2] (another pseudocode shortcut I see from time to time) that does not require copy for passing part of a list as a parameter ?
Count(array A, length n)
if n = 1 return 0
else
x = Count(1st half of A, n/2)
y = Count(2nd half of A, n/2)
return x + y
Without such a mechanism I will pass indices as necessary.
The answer is no. You'll have to pass indices (or slice objects).
You could also write a list subclass that handles slices by returning "views" into the original list rather than copies. I've actually tackled this a few times and found it tricky to get completely right, but it's made much easier by the fact that your application doesn't need negative indexing, slice assignment, or the skip parameter. Here's a quick try:
class ListWithAView(list):
class ListView(object):
def __init__(self, list, start, stop, step):
self.list = list
self.start = start
self.stop = stop
self.step = step
def __iter__(self):
for i in xrange(self.start, self.stop, self.step):
yield self.list[i]
def __len__(self):
return (self.stop - self.start) / self.step
def __getitem__(self, i):
if isinstance(i, slice):
return type(self)(self.list, (i.start or 0) + self.start,
min(self.start + (i.stop or 0), self.stop),
i.step * self.step if i.step else self.step)
if isinstance(i, int) and i < len(self):
return self.list[i+self.start]
raise IndexError("invalid index: %r" % i)
def __setitem__(self, i, v):
if isinstance(i, int):
self.list[i+self.start] = v
else:
raise IndexError("invalid index: %r" % i)
def __repr__(self):
return "<slice [%s:%s:%s] of list id 0x%08x>: %s" % (self.start, self.stop, self.step, id(self.list), self)
def __str__(self):
return str(list(self))
__str__ = __repr__
#property
def view(self):
return self.ListView(self, 0, len(self), 1)
The view property of this list subclass returns a ListView object that acts much like a list, but gets and sets the data in the underlying list rather than storing any items itself. The returned object initially refers to the entire list but can be sliced further if desired. For simplicity, negative steps aren't handled, and you can't do slice assignment, just single items.
Quick demo:
seq = ListViwthAView(range(100))
view = seq.view[10:20][5:7]
view[0] = 1337
print seq[15] # 1337
You can sort of use slice objects here, but unfortunately there isn't a __len__ method, so you have to use (s.start + s.stop)/2 to compute the length. Any time you wise to "materialise" the subarray (which of course creates a copy), you can use A[s]
def count(A, s=None):
if s is None:
s=slice(0, len(A))
if s.start + 1 == s.stop:
return 1
else:
x = count(A, slice(s.start, (s.start + s.stop)/2))
y = count(A, slice((s.start + s.stop)/2, s.stop))
return x + y
print count([1,2,3,4,5])
In your example, the best solution is to just pass the list and the indices as you suggested.
If you didn't need to index into the slices (for example, if just having iterators over the first and second halves of the list was sufficient), you could use the islice function from itertools. E.g.
from itertools import islice
half = (len(sequence) + 1) // 2
first_half = islice(sequence, half):
second_half = islice(sequence, half, len(sequence))
I need to create a message counter object -not to be confused with Python's Counter class. The specification calls for a counter that is initialized to 0, then increments by 1 until it hits 4294967295, at which point it's supposed to cycle back over to 1.
I've implemented a class to do this, but this is just the naive approach. Is there a better way to achieve this goal ?
class MessageCounter():
def __init__(self):
self.value = 0
def increment(self):
if self.value < 4294967295:
self.value += 1
else:
self.reset()
def reset():
self.value = 1
As an alternative to OO, you could create a generating function that yields numbers in sequence, forever. There are a number of ways to do this. In descending order of size and straightforwardness:
def count_loop(upper_limit):
while True:
for i in range(upper_limit):
yield i
gen = count_loop(4294967295)
import itertools
gen = (i for _ in itertools.count() for i in range(4294967295))
gen = (i for _ in iter(int,1) for i in range(4294967295))
You would then retrieve your values by doing next(gen).
>>> next(gen)
0
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
3
(note: Python 2.7 users should use xrange instead of range. However, this may only work for max values smaller than 2^31)
Instead of the reset you can just use the modulo operator:. It will "reset" to 0 instead of one, but that shouldn't matter since you initilized as 0.
def increment(self):
self.value = (value + 1) % 4294967296
I have an example, just more shorter.
class MessageCounter():
def __init__(self):
self.value = 0
def increment(self, reset=False):
self.value = self.value + 1 if self.value < 4294967295 and not reset else 1