2012-01-03 2 views
9

Есть ли \ Как бы вы построили эквивалент python очень полезный collections.defaultdict?defaultdict эквивалент для списков

Воображаемые использование такого контейнера:

>>> a = collections.defaultlist(0) 
>>> a[2]=7 
>>> a[4]='x' 
>>> a 
[0,0,7,0,'x'] 

UPDATE: Я добавил follow up question, чтобы добавить еще больше функциональных возможностей для этой конструкции

+0

Использование JavaScript 'Array' ;-) –

+0

@Josh Lee: Вы читали теги вообще? Нет JavaScript вообще - это вопрос Python. –

+0

Зачем вам это нужно? –

ответ

10

Я думаю, что это будет немного запутанным, чтобы использовать; Однако, вот моя первая мысль о том, как это сделать:

class defaultlist(list): 
    def __init__(self, fx): 
     self._fx = fx 

    def __setitem__(self, index, value): 
     while len(self) <= index: 
      self.append(self._fx()) 
     list.__setitem__(self, index, value) 

Это занимает вызываемым (я думаю, что это как defaultdict работы) для значения по умолчанию.

Когда я бегу:

a = defaultlist(int) 
print a 
a[2] = 7 
a[4] = 'x' 
print a 

я вернусь:

[] 
[0, 0, 7, 0, 'x'] 
+0

Вопрос, похоже, требует, чтобы значение по умолчанию было значением, а чем вызываемый (поэтому в этом отношении отличается от 'defaultdict'). Было бы тривиально приспособить ваш, чтобы соответствовать вопросу (добавьте 'self._fx', а не' self._fx() '). –

+0

Теперь попробуйте 'a [4] = 'x''' a [2] = 7' и увидите ошибку в этом коде. Легко исправить. –

+0

@MarkRansom, хорошо поймать и исправить. – Finn

3

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

(если вы действительно хотите Perl/JS Семантика на этом, вы можете подклассы список __get__ и __set__)

2

Мое предложение:

def xtend(f): 
    def wrap(self, index, *args): 
     if len(self) <= index: 
      self.extend([self._gen()] * (index - len(self) + 1)) 
     return f(self, index, *args) 
    return wrap 

class defaultlist(list): 
    def __init__(self, gen, lst = []): 
     list.__init__(self, lst) 
     self._gen = gen 

    __setitem__ = xtend(list.__setitem__) 
    __getitem__ = xtend(list.__getitem__) 

Результаты:

>>> a = defaultlist(int, [1, 2, 3]) 
>>> a[10] = 'x' 
>>> a[2] = 7 
>>> print a 
[1, 2, 7, 0, 0, 0, 0, 0, 0, 0, 'x'] 
0

Возможно, самый простой способ - использовать dict:

>>> a = {} 
>>> a[2] = 7 
>>> a[4] = 'x' 
>>> [a[i] if i in a else 0 for i in xrange(max(a) + 1)] 
[0, 0, 7, 0, 'x'] 
1

Немного усовершенствованная версия от ответа @Finn.

class defaultlist(list): 
    """List returning default value when accessing uninitialized index. 

    Original implementation: http://stackoverflow.com/a/8719940/315168 
    """ 

    def __init__(self, fx): 
     self._fx = fx 

    def __setitem__(self, index, value): 
     while len(self) <= index: 
      self.append(self._fx()) 
     list.__setitem__(self, index, value) 

    def __getitem__(self, index): 
     """Allows self.dlist[0] style access before value is initialized.""" 
     while len(self) <= index: 
      self.append(self._fx()) 
     return list.__getitem__(self, index) 

 Смежные вопросы

  • Нет связанных вопросов^_^