Исправление индексов массива в Python

Я хотел бы иметь массивы, которые начинаются, скажем, с индекса 4 и доходят до 9. Я не заинтересован в создании пространства памяти для ‹ 4, так как же лучше поступить? Мой 2D-код выглядит следующим образом:

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

Как можно выборочно просто использовать определенный диапазон, т. Е. Где последний индекс работает от 1 до 128 включительно, а не от 0 до 127. Это может быть очевидно, но есть ли способ сделать это?

Спасибо за предложение по словарям, я избегал их - я знаю - большая часть кода, который я конвертирую, взята из C, но я думаю, что словари могут спасти. Есть ли способ сделать то, что я прошу, с массивами?


person disruptive    schedule 21.10.2011    source источник
comment
А нельзя просто диктовками пользоваться?   -  person Gandi    schedule 21.10.2011
comment
Вы можете создать класс на основе списка, а затем переопределить его методы для доступа к элементам. Я не скажу вам, что именно вам нужно изменить (никогда не работал с этим).   -  person rplnt    schedule 21.10.2011
comment
@rplnt: см. docs.python.org/reference/ для магических методов, используемых для эмуляции типов контейнеров. Я предполагаю, что в этом случае вам нужно будет сохранить начальный индекс для вашего пользовательского списка.   -  person Pieter Witvoet    schedule 21.10.2011


Ответы (4)


Для разреженных массивов используйте 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.
person Aaron Digulla    schedule 21.10.2011

Вы можете просто эмулировать список:

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
person phihag    schedule 21.10.2011

Здесь у вас есть два варианта. Вы можете использовать разреженные списки или создать тип контейнера, который в основном имеет обычный список и начальный индекс, чтобы при запросе

specialist.get(4)

вы на самом деле получаете

specialist.innerlist[4 - startidx]
person kojiro    schedule 21.10.2011

Если вам действительно нужна семантика списка и все такое, я полагаю, вы могли бы сделать

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]

но это кажется очень хрупким, если не сказать больше.

person AKX    schedule 21.10.2011