Python/sage: can lists start at index 1?

后端 未结 5 1090
逝去的感伤
逝去的感伤 2021-01-04 13:25

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

相关标签:
5条回答
  • 2021-01-04 13:49

    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.

    0 讨论(0)
  • 2021-01-04 13:51
    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']
    
    0 讨论(0)
  • 2021-01-04 14:04

    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]
    
    0 讨论(0)
  • 2021-01-04 14:04

    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)

    0 讨论(0)
  • 2021-01-04 14:09

    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: Insertion Sort Algorithm

    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.

    0 讨论(0)
提交回复
热议问题