Iam trying to build a priority queue using PriorityQueue in Python, but instead of element to be considered for priority comparison, I want it to use the return value from a function after passing the element to the function , similar to sorted(mtlist,key = myfun), is there a way to achieve this,
Rather than inserting your elements directly into the queue, wrap each element in a tuple, where the first element in the tuple is the desired sorting key. Tuples are sorted by in order of their elements (i.e., first element is compared first), hence why the sorting key needs to come first.
import heapq
queue = []
my_list = [...]
for element in my_list:
heapq.heappush(queue, (my_func(element), element))
If you have a wrapper class for the elements, then you can use operator overloading.
For example, lets say you have a CustomNumber class (equivalent to your elements) where the order is determined by the modulo 16 value (the private function __f()), the you can override the comparison operators like:
class CustomNumber:
def __init__(self, value):
self.value = value
def __f(self, x):
return x % 16
def __lt__(self, obj):
"""self < obj."""
return self.__f(self.value) < self.__f(obj.value)
def __le__(self, obj):
"""self <= obj."""
return self.__f(self.value) <= self.__f(obj.value)
def __eq__(self, obj):
"""self == obj."""
return self.__f(self.value) == self.__f(obj.value)
def __ne__(self, obj):
"""self != obj."""
return self.__f(self.value) != self.__f(obj.value)
def __gt__(self, obj):
"""self > obj."""
return self.__f(self.value) > self.__f(obj.value)
def __ge__(self, obj):
"""self >= obj."""
return self.__f(self.value) >= self.__f(obj.value)
Such that the following code:
a = CustomNumber(16)
b = CustomNumber(14)
print('a < b =', a < b)
print('a <= b =', a <= b)
print('a == b =', a == b)
print('a != b =', a != b)
print('a > b =', a > b)
print('a >= b =', a >= b)
prints:
a < b = True
a <= b = True
a == b = False
a != b = True
a > b = False
a >= b = False
Here is an example of using custom sort in PriorityQueue in Python.
We use a priority-queue (heapq) find the next element to add. To make the
implementation simple we "monkey patch" the ListNode class to have a custom
less-than function using setattr. Note that, simply using the tuple trick
and pushing (node.val, node) to the priority queue will not work because
the lists have values in common.
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
setattr(ListNode, "__lt__", lambda self, other: self.val <= other.val)
pq = []
for l in lists:
if l:
heapq.heappush(pq, l)
out = ListNode(None)
head = out
while pq:
l = heapq.heappop(pq)
head.next = l
head = head.next
if l and l.next:
heapq.heappush( pq, l.next)
return out.next
The way you wrote your question, there is no way to achieve it. According to the documentation:
The lowest valued entries are retrieved first (the lowest valued entry is the one returned by sorted(list(entries))[0]). A typical pattern for entries is a tuple in the form: (priority_number, data).
In other words, the priority is defined by running sorted on the entries, and there is no way there to define the key parameter for that sorted run.
So, you cannot set a sort function when defining the PriorityQueue. You have to use one of the other solutions provided (or write your own PriorityQueue implementation, which should not be too hard).
Edit
After checking the code, I see that the documentation is not an exact description of how it works, but a simplification.
However, it also shows how easy it would be for you to make your own implementation.
Related
class SortedList:
theList = []
def add(self, number):
self.theList.append(number)
return self.theList
def remove(self, number):
self.theList.remove(number)
return self.theList
def printList(self):
return print(self.theList)
def binarSearch(self, number):
middle = (len(self.theList)//2)
end = len(self.theList)
if end != 0:
if int(self.theList[middle]) == int(number):
return print("The number is found in the list at place",middle+1)
elif int(self.theList[middle]) < int(number):
self.theList = self.theList[middle:]
return self.binarSearch(number)
elif int(self.theList[middle]) > int(number):
self.theList = self.theList[:middle]
return self.binarSearch(number)
else:
return print("The list is empty")
sorted = SortedList() #create a SortedList object
sorted.add("1")
sorted.add("2")
sorted.add("3")
sorted.add("4")
sorted.add("5")
sorted.add("6")
sorted.printList()
sorted.binarSearch(3)
I cannot use additional parameters I mut use only self and number. I want to make it recursive but if it is hard you can answer as normal.
This code works good until the number 4. When I give 4 for searching it says it is in place 2 and it continues saying two after 4. I have tried adding other numbers but it is same
Python already has a great module bisect which performs a binary search for sorted lists:
import bisect
l = [2,3,1,5,6,7,9,8,4]
print(bisect.bisect(l, 4)) # Output: 3
Familiarize yourself with this library:
https://docs.python.org/3.5/library/bisect.html
Just a hint: You can use additional parameters if you give them default values. Your method signature would look like this:
def binarSearch(self, number, start=0, end=len(self.theList)):
So it could still be called like sorted.binarySearch(5) but would internally be able to pass the state correctly.
So I need to find the element in the array that will give the maximum value when inputting to the key. Also, if there is more than one element that does that, the first one must be returned. Furthermore, the key parameter must be optional; if not provided, the function must return the first largest element. So far I've come up with
def recursive_max(seq, key = lambda x: x):
if len(seq) == 1:
return seq[0]
else:
m = recursive_max(max(seq, key), key) .......
I'm quite stuck. I don't fully understand recursion but here are the steps I think I need to take.
1) Get element from the list
2) Input the key into the function
3) Initialize the max
4) Compare across the sequence (which is my array)
I'm quite confused how to write this is in code.
If recursion is the requirement, you can just go
def recursive_max(seq, key=lambda x: x):
if len(seq) == 1:
return seq[0]
else:
return max(seq[0], recursive_max(seq[1:], key), key=key)
Here you compare the first element of the array with the maximum of the rest of the array.
Note that the version above is not tail recursive (although it does not matter in Python --- or, at least, in CPython). A tail-recursive version would look like
def recursive_max2(seq, key=lambda x: x):
if len(seq) == 1:
return seq[0]
else:
return _recursive_max(seq[0], seq[1:], key)
def _recursive_max(x, xs, key):
if len(xs) == 0:
return x
else:
return _recursive_max(max(x, xs[0], key=key), xs[1:], key)
I have a list with a few hundred of objects, and I want to check, if a newcomer object is already added to my list (not an equal object, but exactly this exact instance).
I have a dumb realization like this:
def is_one_of(test_object, all_objects):
for elm in all_objects:
if test_object is elm:
return True
return False
Cannot it be more beautiful?
use any:
if any(x is test_object for x in all_objects):
The example in the python reference looks remarkably similar to your code already :)
Use the any() function:
def is_one_of(test_object, all_objects):
return any(test_object is elm for elm in all_objects)
It'll stop iterating over the generator expression as soon as a True result is found.
Eh, I made it by putting id(element) to a set:
def _unit_list(self):
"""
Returns all units in the order they should be initialized.
(Performs search by width from start_point).
"""
unit_id_set = set()
unit_list = []
unit_id_set.add(self.start_point)
unit_list.append(self.start_point)
pos = 0
while pos < len(unit_list):
cur_unit = unit_list[pos]
for child in cur_unit.links_to:
if not (id(child) in unit_id_set):
unit_list.append(child)
unit_id_set.add(id(child))
pos += 1
return unit_list
You can use
if any(test_object is x for x in all_objects): ...
if you need to do this test often however may be you can keep a set of all object ids instead
all_ids = set(map(id, all_objects))
then you can check faster with
if id(test_object) in all_ids: ...
Another common solution that may apply is to store in the object itself in a specific field if it has been already processed:
# add the object to the list
all_objects.append(x)
x.added = True
...
# Check if already added
if test_object.added: ...
I think you're looking for the in operator. The equivalent function would be:
def is_one_of(test_object, all_objects):
return test_object in all_objects
(but you really wouldn't want to write that as a function).
Edit: I'm wrong. According to the Expressions page:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
That would work if your class doesn't define __eq__, but that's more fragile than I'd want to rely on. For example:
class ObjWithEq(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
a = ObjWithEq(1)
b = ObjWithEq(1)
assert a == b
assert a in [b]
class ObjWithoutEq(object):
def __init__(self, val):
self.val = val
a = ObjWithoutEq(1)
b = ObjWithoutEq(1)
assert a != b
assert a not in [b]
I'm trying to create a method that will count all the items in a nested list. So count([[3, 2] , [2]]) == 3. However, it's a Class attribute so I can't just simply do:
def count(L, target):
s = 0
for i in L:
if isinstance(i, list):
s += count(i, target)
else:
if i == target:
s += 1
return s
Rather, I tried to do this, but I get a max recursion depth error. I'm not sure why. Before you look at the code, there's a few things to keep in mind: (1) I expect the base list given to only contain lists so it will have the format: [ [], ]. Also (2) the sub lists will not contain anything except items: [ [item, item], [item] ] :
def count(self, stack=None):
n = 0
if stack:
n += len(stack)
else:
for i in self._items:
if isinstance(i, list):
n += self.count(i)
return n
if stack:
Empty lists are considered false in a boolean context. You want if stack is not None.
Why use recursion, though? You don't need it.
def count(self):
return sum(len(item) for item in self._items)
If your lists are only nested one level deep, this is easy.
class MyClass:
def __init__(self, items):
self.items = items
def count(self):
return sum(len(x) for x in self.items)
a = MyClass([[3,2],[2]])
b = MyClass([[1,2,3],[4,5,6],[7],[]])
print(a.count()) # 3
print(b.count()) # 7
I'm looking for a function that returns a linked list that doesn't contain a specific node.
Here is an example implementation:
Nil = None # empty node
def cons(head, tail=Nil):
""" Extends list by inserting new value. """
return (head, tail)
def head(xs):
""" Returns the frst element of a list. """
return xs[0]
def tail(xs):
""" Returns a list containing all elements except the first. """
return xs[1]
def is_empty(xs):
""" Returns True if the list contains zero elements """
return xs is Nil
def length(xs):
"""
Returns number of elements in a given list. To find the length of a list we need to scan all of its
elements, thus leading to a time complexity of O(n).
"""
if is_empty(xs):
return 0
else:
return 1 + length(tail(xs))
def concat(xs, ys):
""" Concatenates two lists. O(n) """
if is_empty(xs):
return ys
else:
return cons(head(xs), concat(tail(xs), ys))
How can a remove_item function be implemented?
def remove_item(xs, value):
if is_empty(xs):
return xs
elif head(xs) == value:
return tail(xs) # or remove_item(tail(xs), value) to remove all
else:
return cons(head(xs), remove_item(tail(xs), value))
Note: I am not a Lisp programmer, I haven't necessarily done this the best possible way.
[Edit: I might have misinterpreted what you meant by removing a specific node. If you're starting with a suffix of xs rather than a value in xs then the principle is the same but the test involving value is different]
If you want a tail-recursive solution, you can say:
def remove_item(xs, value):
before_rev, after = split_remove(Nil, xs, value)
return reverse_append(before_rev, after)
def reverse_append(a, b):
if is_empty(a):
return b
else:
return reverse_append(tail(a), cons(head(a),b))
def split_remove(before_rev, xs, value):
if is_empty(xs):
return (before_rev, xs)
elif head(xs) == value:
return (before_rev, tail(xs))
else:
return split_remove(cons(head(xs), before_rev), tail(xs), value)
Although I don't know if Python does tail-call optimization