I've downloaded from a supposedly serious source a sage script. It doesn't work on my computer, and a quick debugging showed that a problem came from the fact that at some point, the authors were doing as if a n-element list was numbered from 1 to n (whereas the “normal” numbering in Python and (thus) sage is 0..n-1).
What am I missing? Is there a global variable hidden somewhere that changes this convention, like in APL?
Thanks for your help (I hope my question is clear despite my feeble grasp of both English and CSish...)
Python (and therefore sage) lists are always numbered from 0, and there isn't a way to change that.
Looking at CPython's source, in http://hg.python.org/cpython/file/70274d53c1dd/Objects/listobject.c on line 449:
static PyObject *
list_item(PyListObject *a, Py_ssize_t i)
{
if (i < 0 || i >= Py_SIZE(a)) {
if (indexerr == NULL) {
indexerr = PyString_FromString(
"list index out of range");
if (indexerr == NULL)
return NULL;
}
PyErr_SetObject(PyExc_IndexError, indexerr);
return NULL;
}
Py_INCREF(a->ob_item[i]);
return a->ob_item[i];
}
The item lookup delegates straight to the underlying C array, and C arrays are always zero-based. So Python lists are always zero-based as well.
A simple class that shifts the index for you provides a clean interface to something reusable.
class Array(object):
def __init__(self, items: list) -> None:
self.items = items
def __repr__(self) -> str:
return '{}({})'.format(self.__class__.__name__, self.items)
def __len__(self) -> int:
return len(self.items)
def __contains__(self, item: any) -> bool:
return item in self.items
def __getitem__(self, key: int) -> any:
return self.items[key - 1]
def __setitem__(self, key: int, value: any) -> None:
self.items[key - 1] = value
def __delitem__(self, key: int) -> None:
del self.items[key - 1]
Well I too was facing the same idea on how to implement the method of indexing to be start from 1.
I wanted to implement the Insertion Sort Algorithm which is as follows:
As we already know python list start from 0, what I did was following:
A = ['dummy',5,2,6,4,1,3]
for j in range(2,len(A)):
key = A[j]
i=j-1
while i>0 and A[i]>key:
A[i+1] = A[i]
i = i-1
A[i+1] = key
A.pop(0)
print A
I Just added a 'Dummy' in index 0, did all the work like in Algorithm and removed the 'dummy' again. This was just a cheating method.
I would suggest subclassing e.g. collections.abc.MutableSequence for something like this, because once the protocol (in this case: __getitem__, __setitem__, __delitem__, __len__, insert) is implemented all list methods should work on the custom sequence type.
The solution I came up with uses collections.abc.MutableSequence with a list wrapper (_lst) and a helper class component that doesn't know much about anything except that it is subscriptable, i.e. it implements __getitem__ which handles the index modification.
import collections.abc
class _IndexComponent:
def __getitem__(self, index):
if index == 0: raise IndexError("Index 0 is a lie.")
if index > 0: return index -1
else: return index
class OneList(collections.abc.MutableSequence):
def __init__(self, init: list = None) -> None:
self._index_comp = _IndexComponent()
self._lst = []
if not init is None: # and isinstance(init, list)?
self._lst.extend(init)
def __getitem__(self, index: int) -> any:
return self._lst[self._index_comp[index]]
def __setitem__(self, index: int, val: any) -> None:
self._lst[self._index_comp] = val
def __delitem__(self, index: int) -> None:
del self._lst[self._index_comp[index]]
def __len__(self) -> int:
return len(self._lst)
def insert(self, index: int, val: any) -> None:
self._lst.insert(self._index_comp[index], val)
def __repr__(self) -> str:
return f"{self._lst}"
Now for example pop works although it isn't explicitly implemented:
ol = OneList([1,2,3,4])
print(ol.pop(1))
ol.pop(0) # IndexError
Somehow this feels kind of messy though, I would appriciate if someone shared a better solution.
l = []
l.extend([])
print(l)
In [1]: index_0 = ['foo', 'bar', 'quux']
In [2]: index_1 = [None] + index_0
In [3]: index_1[1]
Out[3]: 'foo'
In [4]: index_1[1:]
Out[4]: ['foo', 'bar', 'quux']
Related
I've created my Node and Stack classes, but I can't figure out how I can display the repr in the Stack class in order to be able to print all items currently in the stack? I've been trying to concatenate the nodes but I'm not sure how since the Stack() doesn't allow iterating through the way a list does?
The stack works as it should, I just don't know how to display it's contents?
Here is my code:
class Stack:
class Node:
def __init__(self, elem, next):
self.elem = elem
self.next = next
def __repr__(self):
return str(self.elem)
def __init__(self):
self._stack = None
self._size = 0
def __repr__(self):
# *Not sure how to implement this properly*
s = ''
for i in range(self._size):
last = self._stack.elem
s += (str(last))+ ', '
self._stack.elem = self._stack.next
return
def push(self, elem):
if self._stack == None:
self._stack = self.Node(elem, None)
self._size += 1
else:
self._stack = self.Node(elem, self._stack)
self._size += 1
def pop(self):
if self._stack == None:
raise Exception ('This Stack is empty!')
else:
last = self._stack.elem
self._stack = self._stack.next
self._size -= 1
return last
def top(self):
return self._stack.elem
def isEmpty(self):
return self._size == 0
Example:
s= Stack()
s.push(4)
s.push(9)
s.push("joe")
s
joe, 9, 9,
Thank you in advance.
A way simpler implementation that avoids all the problems and pitfalls of your solution:
from typing import Iterable, Any
class Stack:
def __init__(self, xs: Iterable = None):
self._items = [] if xs is None else list(xs)
def push(self, elem: Any):
self._items.append(elem)
def pop(self) -> Any:
return self._items.pop()
def top(self) -> Any:
return self._items[-1]
def isEmpty(self) -> bool:
return not self._items
def __repr__(self) -> str:
typename = type(self).__name__
return f'{typename}({self._items})'
def __str__(self) -> str:
return ', '.join(str(x) for x in self._items)
s = Stack()
s.push(4)
s.push(9)
s.push("joe")
print(s)
print(repr(s))
But note that there's little use to a class like this over just using a list like a stack to begin with.
The output:
4, 9, joe
Stack([4, 9, 'joe'])
Note that this has the top element at the end, you could reverse it if you like of course.
If you insist on a working __repr__ for your specific implementation, using __repr__ as you intend in a non-standard way, something like this would work:
def __repr__(self):
p = self._stack
elems = []
while p is not None:
elems.append(p.elem)
p = p.next
return ', '.join(elems)
But note that there's several other issues with your implementation, other than this not being a correct __repr__, as previously pointed out here and in the comments. Your 'node' has a __repr__ which just returns its element value (which isn't a valid representation at all in most cases); you seem to be using __repr__ where you're really after __str__.
If this were an assignment in programming class, I'm not sure I'd award a passing grade, depending on what the aim was.
I am trying to build a max stack in python, I am not sure what I am doing wrong.
Here is the question>
Design a max stack data structure that supports the stack operations
and supports finding the stack's maximum element.
Implement the MaxStack class:
MaxStack() Initializes the stack object.
void push(int x) Pushes element x onto the stack.
int pop() Removes the element on top of the stack and returns it.
int top() Gets the element on the top of the stack without removing it.
int peekMax() Retrieves the maximum element in the stack without removing it.
int popMax() Retrieves the maximum element in the stack and removes it.
If there is more than one maximum element, only remove the top-most one.
class MaxStack:
def __init__(self):
self.stack = []
self.stack_max = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.stack_max or x > self.stack_max[-1][0]:
self.stack_max.append([x, 1])
elif x == self.stack_max[-1][0]:
self.stack_max[-1][1] += 1
else:
self.stack_max.append(self.stack_max[-1])
def pop(self) -> int:
if not self.stack_max or self.stack:
return
if self.stack_max[-1][0] == self.stack[-1]:
self.stack_max[-1][1] -= 1
if self.stack_max[-1][1] == 0:
del self.stack_max[-1]
return self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def peekMax(self) -> int:
if self.stack_max:
return self.stack_max[-1][0]
def popMax(self) -> int:
if self.stack_max:
return self.stack_max.pop()[0]
Example code:
obj = MaxStack()
obj.push(6)
param_2 = obj.pop()
param_3 = obj.top()
param_4 = obj.peekMax()
param_5 = obj.popMax()
Input :
["MaxStack","push","push","push","top","popMax","top","peekMax","pop","top"] [[],[5],[1],[5],[],[],[],[],[],[]]
Output:
[null,null,null,null,5,5,5,5,None,5]
Expected:
[null,null,null,null,5,5,1,5,1,5]
Reference: Leetcode 716. Max Stack
class MaxStack:
def __init__(self,value):#taking some value to avoid empty obj
self.stack=[value]
self.max_=[value,0]
self.length=1
def push(self,value):
self.stack.append(value)
self.length+=1
if value>self.max_[0]:
self.max_[0],self.max_[1]=value,self.length-1
def pop(self):
if self.length==0:
return
elif self.stack[-1]==self.max_[0]:
self.popMax()
else:
self.stack.pop()
self.length-=1
def top(self):
print(self.stack[-1])
def peekMax(self):
print(self.max_[0])
def popMax(self):
if self.length==0 or self.max_[1]==-1:
return
self.stack.pop(self.max_[1])
self.length-=1
self.max_[0],self.max_[1]=-1,-1
for i in range(self.length):
if self.stack[i]>self.max_[0]:
self.max_[0],self.max_[1] = self.stack[i],i
Sorry for the improper indentations, I tried a lot to fix it. Anyways this should work and I wanted to try it out on leetcode but it needs a login. Let me know if there is any issue.
To me, it seems a little confusing to track the count in the tuple of the value, when you could just continue adding to the max stack and counting them from the list if you need that.
class MaxStack:
def __init__(self):
self.stack = []
self.maxes = []
def push(self, n):
self.stack.append(n)
if not self.maxes or n >= max(self.maxes):
self.maxes.append(n)
def pop(self):
if self.stack:
val = self.stack.pop()
if val in self.maxes:
self.maxes.remove(val)
def top(self):
if self.stack:
return self.stack[-1]
def peek_max(self):
if self.maxes:
return self.maxes[-1]
def pop_max(self):
if self.maxes:
return self.maxes.pop()
Then if you need the count of the number of each, just use count():
def max_count(self):
if self.maxes:
return self.maxes.count(max(self.maxes))
Alright so all lists have __setitem__ and __getitem__ and ints have __add__ __sub__ and such to operate on their value. But where is that value actually stored / how can I reference it? Say I want to make a class imitating an list. It might look something like this
class Memory(object):
def __init__(self):
self.data = []
def __getitem__(self, i):
return self.data[i]
def __setitem__(self, key, item):
self.data[key] = item
This isn't very efficient, and I'd have to most likely write every single method of the class individually, which can span hundreds of lines with multiple classes.
The next best solution to create the class being a child of a list like:
class Memory(list):
...
But you can't edit any of its methods because you can't reference its value. If you changes its __setitem__()
What I was wanting to do with this is to create a list class so I can set the list's and do other operations values all on one lambda. I can't just simply directly call __setitem__(key,item) because you can't input a key outside of the range of the items already present in the list. How would I be able to edit the list's value without calling its __setitem__() method.
I realize this doesn't directly answer your question about "where is the value ... stored", and I'm not sure what you mean by "I can't just simply directly call __setitem__(key,item) because you can't input a key outside of the range of the items already present in the list," but if I understand you correctly, you just have to "fill in" values in between the value you want to set and the current length.
For example, I have a utility class that I sometimes use to do this. (See the test cases at the bottom for an idea of how I use it.)
class DynamicArray(list):
''' Just like a normal list except you can skip indices when you fill it. '''
def __init__(self, defaultVal = None, startingCapacity = 0):
super(DynamicArray, self).__init__()
self.defaultVal = defaultVal
if (startingCapacity > 0):
self += [ defaultVal ] * startingCapacity
def insert(self, ind, val):
if (ind > len(self)):
for i in xrange(len(self), ind):
self.append(self.defaultVal)
super(DynamicArray, self).insert(ind, val)
def set(self, ind, val):
self[ind] = val
def __setitem__(self, ind, val):
if (ind >= len(self)):
for i in xrange(len(self), ind + 1):
self.append(self.defaultVal)
super(DynamicArray, self).__setitem__(ind, val)
if __name__ == "__main__":
a = DynamicArray()
assert(len(a) == 0)
a[3] = 2
assert(a[3] == 2)
assert(a[0] is None and a[1] is None and a[2] is None)
assert(len(a) == 4)
a[1] = 1
assert(a[1] == 1)
assert(a[3] == 2)
assert(a[0] is None and a[2] is None)
assert(len(a) == 4)
a[5] = 7
assert(a[5] == 7)
assert(a[3] == 2)
assert(a[1] == 1)
assert(a[0] is None and a[2] is None)
assert(len(a) == 6)
I'd like to have arrays that start from say an index of 4 and go to 9. I'm not interested in creating memory space for < 4, so how is best to proceed? My 2D code is as follows:
arr = [[ 0 for row in range(2)] for col in range(1, 129)]
>>> arr[0][0] = 1
>>> arr[128][0] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: list index out of range
>>> arr[127][0] = 1
How can selectively just use the specific range i.e. where the last index runs from 1 to 128 inclusive not 0 to 127. This maybe obvious, but is there a way to do this?
Thanks for the suggestion for dicts, I have been avoiding these - I know - much of the code I'm converting is from C, but I think dictionaries might the saviour. Is there a way to do what I am asking with arrays?
For sparse arrays, use a dict:
sparseArray = {}
sparseArray[(0,0)] = 1
sparseArray[(128,128)] = 1
print sparseArray # Show the content of the sparse array
print sparseArray.keys() # Get all used indices.
You can simply emulate a list:
class OffsetList(object):
def __init__(self, offset=4):
self._offset = offset
self._lst = []
def __len__(self):
return len(self._lst)
def __getitem__(self, key):
return self._lst[key - self._offset]
def __setitem__(self, key, val):
self._lst[key - self._offset] = val
def __delitem__(self, key):
del self._lst[key - self._offset]
def __iter__(self):
return iter(self._lst)
def __contains__(self, item):
return item in self._lst
# All other methods go to the backing list.
def __getattr__(self, a):
return getattr(self._lst, a)
# Test it like this:
ol = OffsetList(4)
ol.append(2)
assert ol[4] == 2
assert len(ol) == 1
You have two options here. You can use sparse lists, or you can create a container type that basically has a normal list and a start index, such that when you request
specialist.get(4)
you actually get
specialist.innerlist[4 - startidx]
If you really wanted list semantics and all, I suppose you could do
class OffsetyList(list):
def __init__(self, *args, **kwargs):
list.__init__(self, *args)
self._offset = int(kwargs.get("offset", 0))
def __getitem__(self, idx):
return list.__getitem__(self, idx + self._offset)
def __setitem__(self, idx, value):
list.__setitem__(self, idx + self._offset, value)
# Implementing the rest of the class
# is left as an exercise for the reader.
ol = OffsetyList(offset = -5)
ol.extend(("foo", "bar", "baz"))
print ol[5], ol[7], ol[6]
but this seems very fragile to say the least.
Thanks to some great folks on SO, I discovered the possibilities offered by collections.defaultdict, notably in readability and speed. I have put them to use with success.
Now I would like to implement three levels of dictionaries, the two top ones being defaultdict and the lowest one being int. I don't find the appropriate way to do this. Here is my attempt:
from collections import defaultdict
d = defaultdict(defaultdict)
a = [("key1", {"a1":22, "a2":33}),
("key2", {"a1":32, "a2":55}),
("key3", {"a1":43, "a2":44})]
for i in a:
d[i[0]] = i[1]
Now this works, but the following, which is the desired behavior, doesn't:
d["key4"]["a1"] + 1
I suspect that I should have declared somewhere that the second level defaultdict is of type int, but I didn't find where or how to do so.
The reason I am using defaultdict in the first place is to avoid having to initialize the dictionary for each new key.
Any more elegant suggestion?
Thanks pythoneers!
Use:
from collections import defaultdict
d = defaultdict(lambda: defaultdict(int))
This will create a new defaultdict(int) whenever a new key is accessed in d.
Another way to make a pickleable, nested defaultdict is to use a partial object instead of a lambda:
from functools import partial
...
d = defaultdict(partial(defaultdict, int))
This will work because the defaultdict class is globally accessible at the module level:
"You can't pickle a partial object unless the function [or in this
case, class] it wraps is globally accessible ... under its __name__
(within its __module__)"
-- Pickling wrapped partial functions
Look at nosklo's answer here for a more general solution.
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
Testing:
a = AutoVivification()
a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6
print a
Output:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
As per #rschwieb's request for D['key'] += 1, we can expand on previous by overriding addition by defining __add__ method, to make this behave more like a collections.Counter()
First __missing__ will be called to create a new empty value, which will be passed into __add__. We test the value, counting on empty values to be False.
See emulating numeric types for more information on overriding.
from numbers import Number
class autovivify(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value
def __add__(self, x):
""" override addition for numeric types when self is empty """
if not self and isinstance(x, Number):
return x
raise ValueError
def __sub__(self, x):
if not self and isinstance(x, Number):
return -1 * x
raise ValueError
Examples:
>>> import autovivify
>>> a = autovivify.autovivify()
>>> a
{}
>>> a[2]
{}
>>> a
{2: {}}
>>> a[4] += 1
>>> a[5][3][2] -= 1
>>> a
{2: {}, 4: 1, 5: {3: {2: -1}}}
Rather than checking argument is a Number (very non-python, amirite!) we could just provide a default 0 value and then attempt the operation:
class av2(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value
def __add__(self, x):
""" override addition when self is empty """
if not self:
return 0 + x
raise ValueError
def __sub__(self, x):
""" override subtraction when self is empty """
if not self:
return 0 - x
raise ValueError
Late to the party, but for arbitrary depth I just found myself doing something like this:
from collections import defaultdict
class DeepDict(defaultdict):
def __call__(self):
return DeepDict(self.default_factory)
The trick here is basically to make the DeepDict instance itself a valid factory for constructing missing values. Now we can do things like
dd = DeepDict(DeepDict(list))
dd[1][2].extend([3,4])
sum(dd[1][2]) # 7
ddd = DeepDict(DeepDict(DeepDict(list)))
ddd[1][2][3].extend([4,5])
sum(ddd[1][2][3]) # 9
def _sub_getitem(self, k):
try:
# sub.__class__.__bases__[0]
real_val = self.__class__.mro()[-2].__getitem__(self, k)
val = '' if real_val is None else real_val
except Exception:
val = ''
real_val = None
# isinstance(Avoid,dict)也是true,会一直递归死
if type(val) in (dict, list, str, tuple):
val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
# 重新赋值当前字典键为返回值,当对其赋值时可回溯
if all([real_val is not None, isinstance(self, (dict, list)), type(k) is not slice]):
self[k] = val
return val
def _sub_pop(self, k=-1):
try:
val = self.__class__.mro()[-2].pop(self, k)
val = '' if val is None else val
except Exception:
val = ''
if type(val) in (dict, list, str, tuple):
val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
return val
class DefaultDict(dict):
def __getitem__(self, k):
return _sub_getitem(self, k)
def pop(self, k):
return _sub_pop(self, k)
In[8]: d=DefaultDict()
In[9]: d['a']['b']['c']['d']
Out[9]: ''
In[10]: d['a']="ggggggg"
In[11]: d['a']
Out[11]: 'ggggggg'
In[12]: d['a']['pp']
Out[12]: ''
No errors again.
No matter how many levels nested.
pop no error also
dd=DefaultDict({"1":333333})