Implementation of a Stack - python

I'm confused with this Stack implementation (ADT). Mainly with adding and removing options, but also by using empty dictionary, instead of empty list.
Here is my problem:
By using an empty list, removing and adding implementations are understandable:
class Stack:
def __init__(self):
self.elements = []
def add(self, item):
self.elements.append(item)
def remove(self):
self.elements.pop()
However, I'm confusing such implementations for an empty dictionary:
class D:
def __init__(self):
self.elements = {}
self.index = 0 # since only adding one element per add method
# better to use indexing for key1, then key2
def add(self, item):
# For dictionary better to use
# self.elements[item] = new_item
# but in stack we adding one element
self.elements[item] = self.index
self.index = item
def remove(self):
self.elements.pop(self.index)
For this code, I want to create new dictionary after adding two elements:
For instance we add(7), add(8) and we get {7:8}. But instead, after adding more elements, like add(9) and add(10), I got {7:8}, {8:9}, {9:10}.
How do I deal with that? My remove method working fine, but adding seems not great.

Related

Calling a linked list

I'm new to programming, so excuse the possibly stupid question.
I'm doing leetcodes and I got to the linked lists. I think I understand them okay, it's just that I don't know how to test my code/call my function(?)
Problem I'm working on
Here's my code, I know it works since I uploaded it onto leetcode, but I would still like to be able to run it on my machine.
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
I guess I have two different problems:
the "Optional[ListNode]) -> Optional[ListNode]:" part
and the actual calling of the function
Some questions before used the "typing" module functions like "List", so I would simply import them and they wouldn't be a problem. But I'm not really sure what to do here
To check my solutions, I write a short piece of code that I can put example inputs into
Solution = Solution()
print(Solution.middleNode(head = [1,2,3,4,5,6]))
But isn't the "head" there, just a normal list? Do I have to create an extra function separately to create the "links". I've seen the creation of a linked list done by calling a function every time you want to add a new node. So would I use a for loop to add my example case?
well if you looking for internal boilerplate, below is code for that.
here you need to create classes for nodes, linked list and solutions,.
then with the given number, you need to create a linkedlist object.
this above part is done in leetcode by themself and this object is passed to class Solution method middleNode, where OP code run and give result. next once output is got it is compared with existing solution
# Node class for individual nodes
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# linked list class, to create a linked list of the list nodes
class LinkedList:
def __init__(self):
self.head = None
# adding a node element to linked list
def add(self, node):
if self.head is None:
self.head = node
else:
curr = self.head
while curr.next:
curr = curr.next
curr.next = node
curr = node
# printing element of existing linked list
def print_ll(self):
curr= self.head
while curr:
print(curr.val)
curr= curr.next
# leetcode solution class
class Solution:
def middleNode(self, head) :
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
# value with which we create list nodes
values = [1,2,3,4,5,6,7,8,9,10]
ll = LinkedList() # create a linked list class object
for i in values:
node = ListNode(i) # creating a list node
ll.add(node) # adding list node to linked list
#ll.print_ll() # printing linked list
x = Solution().middleNode(ll.head) # passing linked list object to leetcode solution method and getting result
while x: # printing result
print(x.val)
x=x.next
I think the problem on LeetCode is poorly worded. head = [1,2,3,4,5] is not really a head as it should only refer to the first item in the list - there seems to be a bit of hidden boilerplate code that creates a linked list from input list and an output list from output node.
Here's an example code that works similiar to the LeetCode task.
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
inp = [1,2,3,4,5,6]
next = None
for i in reversed(inp):
next = ListNode(i, next) # next points to head at the end of the loop
res = Solution().middleNode(next)
out = []
while res:
out.append(res)
res = res.next
print([o.val for o in out])
to make your code work on your machine you have to implement a couple of things:
First, for your first answer, you have to implement the class ListNode given at the top of the leetcode-page:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
The you import "Optional" from typing:
from typing import Optional
Then you have the prerequisites for your code.
You have to initialise the class, as you have mentioned. The only problem here is, that your variable has the same name as your class, what could cause trouble later.
To finish, you have to call your function as you already did, with one little difference: This function has to be called with "head" as a variable of type ListNode, not List, and gives you back a variable of the type ListNode.
In a nutshell, this would be my solution (of course you can and as much ListNodes as you want):
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
# Initialise class
s = Solution()
# Defining nodes of the list, assigning always the next node.
seven = ListNode(7)
six = ListNode(6, next=seven)
five = ListNode(5, next=six)
four = ListNode(4, next=five)
three = ListNode(3, next=four)
two = ListNode(2, next=three)
one = ListNode(1, next=two)
# Calling your function (with "one" as your head node of the list)
# NOTE: As this gives you back an attribute of type ListNode, you have to access the "val" attribute of it to print out the value.
print(s.middleNode(one).val)

Compiling a list : python best practice

I am often compiling lists one element at a time in python 3; say for instance I am making a list by going through a linked list with first element head:
l = []
while head:
l.append(head.val)
head = head.next
I was wondering what the best practices are. Is there another way of writing this? Could it be possible to describe the list in one line, with something like this instead:
while head:
l = # something creating the list AND appending elements
head = head.next
Even better: do I always have to use a loop to create lists in similar cases, or are there often ways to make the desired list in one line ?
Thanks!
EDIT : a typo in the code !
From an OOP perspective, the best practice is to rely on Python's __iter__ method to cast an iterable to a list.
I am assuming your linked-list class looks a bit like this.
class LinkedList:
def __init__(self, value, nxt=None):
self.value = value
self.next = nxt
To allow iteration on your linked-list, you can define __iter__
class LinkedList:
def __init__(self, value, nxt=None):
self.value = value
self.next = nxt
def __iter__(self):
while self:
yield self.value
self = self.next
You can then let list handle the cast of the LinkedList iterable.
head = LinkedList(1, LinkedList(2, LinkedList(3)))
lst = list(head) # [1, 2, 3]

I am trying make a function that takes a number as a parameter and removes all occurrences of it from a Queue

class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def add(self, item):
self.items.append(item)
def remove(self):
self.items.reverse()
return self.items.pop()
I need to create a function that takes in a number as a parameter and a queue then removes every occurrence of that number in the queue but with the exception of the omissions. I've put up a model of what my Queue looks like above and I'll put a model of what the queue should somewhat look like (It's very messy and in its early stages) below.
def remove_item(q, val):
q_temp = Queue
while not q.is_empty():
q_temp.add(q.remove)
remove_item()
I cannot directly modify it in any way and I can't put the elements of the Queue in a normal list. Anyone got any solutions?
Edit: Also it needs to be executable in IDLE like this
remove_item(queue,number)
What I would do is something like this:
number_to_remove = 123
for i in range(0, queue.length()):
number = queue.remove()
if number != number_to_remove:
queue.add(number)
That way you "loop" trough the queue, you look at every number and if it's not the number you should remove then just add it again. You need to create the .length() method though.
That code will fail because bad indentation:
def remove_item(q, val):
#> q_temp = Queue
And you're setting q_temp to the class, not to an instance, making that it can't be modified.
q_temp = Queue()
And, the .remove method doesn't work, there's an easier way to make it work:
def remove(self):
return self.items.pop(-1)
But I don't have a (fully valid) answer. I we could get the queue's items, I'd use conditional list comprehensions for deleting determinated items, and applying that into the queue.
def removeFromQueue(queue, value = ""):
items = queue.items
queue.items = [i for i in items if i != value]
return queue
You can do if you let us to use the Queue class use only the class methods (we can make variables, make another queues, .remove and .add numbers, but not to use .items) you can do this:
def removeFromQueue(queue, value = ""):
items = []
for i in len(queue):
items.append(queue.remove())
items = [i for i in items if i != value]:
for i in items:
queue.add(items.pop(0))
I don't think that's valid, though. And it would need defining Queue.__len__()*:
def __len__(self):
return len(self.items)
* or modififying the code and defining __iter__ or some sort of thing like that

Python set with the ability to pop a random element

I am in need of a Python (2.7) object that functions like a set (fast insertion, deletion, and membership checking) but has the ability to return a random value. Previous questions asked on stackoverflow have answers that are things like:
import random
random.sample(mySet, 1)
But this is quite slow for large sets (it runs in O(n) time).
Other solutions aren't random enough (they depend on the internal representation of python sets, which produces some results which are very non-random):
for e in mySet:
break
# e is now an element from mySet
I coded my own rudimentary class which has constant time lookup, deletion, and random values.
class randomSet:
def __init__(self):
self.dict = {}
self.list = []
def add(self, item):
if item not in self.dict:
self.dict[item] = len(self.list)
self.list.append(item)
def addIterable(self, item):
for a in item:
self.add(a)
def delete(self, item):
if item in self.dict:
index = self.dict[item]
if index == len(self.list)-1:
del self.dict[self.list[index]]
del self.list[index]
else:
self.list[index] = self.list.pop()
self.dict[self.list[index]] = index
del self.dict[item]
def getRandom(self):
if self.list:
return self.list[random.randomint(0,len(self.list)-1)]
def popRandom(self):
if self.list:
index = random.randint(0,len(self.list)-1)
if index == len(self.list)-1:
del self.dict[self.list[index]]
return self.list.pop()
returnValue = self.list[index]
self.list[index] = self.list.pop()
self.dict[self.list[index]] = index
del self.dict[returnValue]
return returnValue
Are there any better implementations for this, or any big improvements to be made to this code?
I think the best way to do this would be to use the MutableSet abstract base class in collections. Inherit from MutableSet, and then define add, discard, __len__, __iter__, and __contains__; also rewrite __init__ to optionally accept a sequence, just like the set constructor does. MutableSet provides built-in definitions of all other set methods based on those methods. That way you get the full set interface cheaply. (And if you do this, addIterable is defined for you, under the name extend.)
discard in the standard set interface appears to be what you have called delete here. So rename delete to discard. Also, instead of having a separate popRandom method, you could just define popRandom like so:
def popRandom(self):
item = self.getRandom()
self.discard(item)
return item
That way you don't have to maintain two separate item removal methods.
Finally, in your item removal method (delete now, discard according to the standard set interface), you don't need an if statement. Instead of testing whether index == len(self.list) - 1, simply swap the final item in the list with the item at the index of the list to be popped, and make the necessary change to the reverse-indexing dictionary. Then pop the last item from the list and remove it from the dictionary. This works whether index == len(self.list) - 1 or not:
def discard(self, item):
if item in self.dict:
index = self.dict[item]
self.list[index], self.list[-1] = self.list[-1], self.list[index]
self.dict[self.list[index]] = index
del self.list[-1] # or in one line:
del self.dict[item] # del self.dict[self.list.pop()]
One approach you could take is to derive a new class from set which salts itself with random objects of a type derived from int.
You can then use pop to select a random element, and if it is not of the salt type, reinsert and return it, but if it is of the salt type, insert a new, randomly-generated salt object (and pop to select a new object).
This will tend to alter the order in which objects are selected. On average, the number of attempts will depend on the proportion of salting elements, i.e. amortised O(k) performance.
Can't we implement a new class inheriting from set with some (hackish) modifications that enable us to retrieve a random element from the list with O(1) lookup time? Btw, on Python 2.x you should inherit from object, i.e. use class randomSet(object). Also PEP8 is something to consider for you :-)
Edit:
For getting some ideas of what hackish solutions might be capable of, this thread is worth reading:
http://python.6.n6.nabble.com/Get-item-from-set-td1530758.html
Here's a solution from scratch, which adds and pops in constant time. I also included some extra set functions for demonstrative purposes.
from random import randint
class RandomSet(object):
"""
Implements a set in which elements can be
added and drawn uniformly and randomly in
constant time.
"""
def __init__(self, seq=None):
self.dict = {}
self.list = []
if seq is not None:
for x in seq:
self.add(x)
def add(self, x):
if x not in self.dict:
self.dict[x] = len(self.list)
self.list.append(x)
def pop(self, x=None):
if x is None:
i = randint(0,len(self.list)-1)
x = self.list[i]
else:
i = self.dict[x]
self.list[i] = self.list[-1]
self.dict[self.list[-1]] = i
self.list.pop()
self.dict.pop(x)
return x
def __contains__(self, x):
return x in self.dict
def __iter__(self):
return iter(self.list)
def __repr__(self):
return "{" + ", ".join(str(x) for x in self.list) + "}"
def __len__(self):
return len(self.list)
Yes, I'd implement an "ordered set" in much the same way you did - and use a list as an internal data structure.
However, I'd inherit straight from "set" and just keep track of the added items in an
internal list (as you did) - and leave the methods I don't use alone.
Maybe add a "sync" method to update the internal list whenever the set is updated
by set-specific operations, like the *_update methods.
That if using an "ordered dict" does not cover your use cases. (I just found that trying to cast ordered_dict keys to a regular set is not optmized, so if you need set operations on your data that is not an option)
If you don't mind only supporting comparable elements, then you could use blist.sortedset.

__getitem__ invocation in for loop

I am learning Python I don't get one thing. Consider this code:
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __getitem__(self,index):
print "index",index
return self.items[index]
def __len__(self):
return len(self.items)
stack = Stack()
stack.push(2)
stack.push(1)
stack.push(0)
for item in stack:
print item
and the output
index 0
2
index 1
1
index 2
0
index 3
Why is getitem called four times?
The for loop doesn't know how to iterate over your object specifically because you have not implemented __iter__(), so it uses the default iterator. This starts at index 0 and goes until it gets an IndexError by asking for index 3. See http://effbot.org/zone/python-for-statement.htm.
Your implementation would be a lot simpler if you derived from list, by the way. You wouldn't need __init__(), pop(), or __getitem__(), and push could be just another name for append. Also, since list has a perfectly good __iter()__ method, for will know how to iterate it without going past the end of the list.
class Stack(list):
push = list.append

Categories

Resources