【问题标题】:Python/sage: can lists start at index 1?Python/sage:列表可以从索引 1 开始吗?
【发布时间】:2011-11-06 13:38:35
【问题描述】:

我从一个据说很严肃的来源下载了一个圣人脚本。它在我的计算机上不起作用,并且快速调试表明问题来自于这样一个事实,即在某些时候,作者正在做一个 n 元素列表从 1 到 n 编号(而“正常”编号在 Python 中,(因此)sage 是 0..n-1)。

我错过了什么?是否有隐藏在某个地方的全局变量会改变这个约定,比如在 APL 中?

感谢您的帮助(尽管我对英语和 CSish 的掌握很弱,但我希望我的问题很清楚......)

【问题讨论】:

  • 您能否至少发布代码的相关部分?
  • (1..n) 符号似乎是 Sage 特定的写作 (stackoverflow.com/questions/3511699/python-1-n-syntax)
  • @CédricJulien 列表在 Sage 中也从 0 开始索引,因为它基于 Python。您提供的链接是一种制作列表的方式...例如 [6..12] 是列表 [6, 7, 8, 9, 10, 11, 12]。但是,此列表中项目的索引将是 0、1、2、3、4、5、6。同样,这是一种制作列表的方式,而不是重新索引列表的方式。

标签: python list sage


【解决方案1】:

Python(以及 Sage)列表总是从 0 开始编号,没有办法改变它。

查看 CPython 的源代码,在第 449 行的http://hg.python.org/cpython/file/70274d53c1dd/Objects/listobject.c

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];
}

项目查找直接委托给底层 C 数组和C arrays are always zero-based。所以 Python 列表也总是从零开始的。

【讨论】:

    【解决方案2】:

    一个为您移动索引的简单类为可重用的东西提供了一个干净的接口。

    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]
    

    【讨论】:

    • 这只是一个非常弱的列表包装器,尽管它不能运行任何实际的列表功能。子类化 collections.abc.MutableSequence 将是 imo 执行此操作的更恰当方式。
    • @upgrd 随时上传更好的实现...
    • 这是我的解决方案:stackoverflow.com/a/64935398/6455731;虽然不是很满意.. :(
    【解决方案3】:

    关于如何实现从 1 开始的索引方法,我也面临同样的想法。 我想实现如下的插入排序算法:

    我们已经知道 python 列表从 0 开始,我所做的如下:

    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
    

    我刚刚在索引 0 中添加了一个“虚拟”,完成了算法中的所有工作,并再次删除了“虚拟”。这只是一种作弊方法。

    【讨论】:

      【解决方案4】:

      我建议子类化,例如collections.abc.MutableSequence 对于这样的事情,因为一旦协议(在这种情况下:__getitem____setitem____delitem____len____len__insert)被实现所有列表方法应该处理自定义序列类型。

      我想出的解决方案使用 collections.abc.MutableSequence 和一个列表包装器 (_lst) 和一个辅助类组件,除了它是可下标的之外,它对任何事情都一无所知,即它实现了 __getitem__ 来处理索引修改。

      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}"
      

      现在例如 pop 工作,虽然它没有明确实现:

      ol = OneList([1,2,3,4])
      print(ol.pop(1))
      ol.pop(0) # IndexError
      

      虽然这感觉有点乱,但如果有人分享更好的解决方案,我会很感激。

      l = [] l.扩展([]) 打印(l)

      【讨论】:

        【解决方案5】:
        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']
        

        【讨论】:

          猜你喜欢
          • 2011-03-26
          • 2013-01-01
          • 2019-09-05
          • 1970-01-01
          • 2016-12-27
          • 2019-12-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多