2013-03-10 7 views
0

Мне нужно построить структуру данных, как этот:python - какую структуру данных использовать в качестве массива dicts?

{ 
    key: {k: v for k in range(fixed_small_number)} 
    for key in range(fixed_large_number) 
} 

Дело в том, что я строить его в «эклектичный» путь, где каждый раз, когда получить еще один пункт, чтобы положить в случайном к для случайный ключ, то есть мне нужен произвольный доступ, и мне нужно, чтобы внутренний dict был изменчивым.

Так что мой вопрос делится на две части:

  1. Рекомендуемый тип для внешнего Dict.

  2. Рекомендуемый тип для внутреннего dict.

«Лучшее» решение для меня было бы массивом изменяемых именованных вершин, только этого не существует.

Я мог бы использовать список именованных вершин, а затем воссоздавать каждый из них с новыми данными, но это звучит невероятно бесполезно, поскольку списки не являются случайными и эффективными и все перезаписи одних и тех же данных.

Есть ли какая-то магическая новая структура, о которой я не знаю?

EDIT: Пример использования:

for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1) ...]: 
    my_structre[key][k] = v 

EDIT2:

получается, что списки на самом деле DO support random access

+0

Я не уверен, что это возможно, если я понимаю вопрос правильно. Переменные объекты, такие как 'dict', не могут быть ключами словаря. – millimoose

+0

В любом случае, неясно, чего вы пытаетесь достичь. Можете ли вы показать пример того, как эта структура данных будет построена «эклектично»? То есть до и после состояний для данного однократного обновления? – millimoose

+0

Я не уверен, что понимаю ... где я предположил, что dicts будет функционировать как ключи? – phistakis

ответ

6

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

class MutableEfficientNamedList(object): 
    __slots__ = ('field1', 'field2', 'field3') 

    def __init__(self, *values): 
     for k, v in zip(self.__slots__, values): 
      setattr(self, k, v) 

    def __getitem__(self, i): 
     return getattr(self, self.__slots__[i]) 

    def __setitem__(self, i, v): 
     return setattr(self, self.__slots__[i], v) 

    def __repr__(self): 
     return '{}({})'.format(type(self).__name__, 
      ', '.join(repr(getattr(self, s)) for s in self.__slots__)) 

затем используйте те, что в вашей структуре. Их можно использовать так же, как и названные кортежи (разрешить доступ по индексу и по имени), но они допускают мутацию. Используя __slots__ след памяти каждого экземпляра остается низким:

>>> menl = MutableEfficientNamedList('foo', 'bar', 'baz') 
>>> menl 
MutableEfficientNamedList('foo', 'bar', 'baz') 
>>> menl.field1 
'foo' 
>>> menl[0] 
'foo' 
>>> menl[1] 
'bar' 
>>> menl[1] = 'spam' 
>>> menl.field2 
'spam' 

Вы, конечно, дать пазами значимые имена, и, пожалуйста, выбрать лучшее название для своего класса, чем то, что я использовал в моем примере. :-)

Для расширения на namedtuple() модели, здесь является родовым завод функция:

def namedlist(name, *attrs): 
    """Create a named list class named `name` with attributes `attrs`. 
     `attrs` must be strings representing valid Python identifiers. 
    """ 
    class MutableEfficientNamedList(object): 
     __slots__ = attrs 

     def __init__(self, *values): 
      for k, v in zip(self.__slots__, values): 
       setattr(self, k, v) 

     def __getitem__(self, i): 
      return getattr(self, self.__slots__[i]) 

     def __setitem__(self, i, v): 
      return setattr(self, self.__slots__[i], v) 

     def __repr__(self): 
      return '{}({})'.format(type(self).__name__, 
       ', '.join(repr(getattr(self, s)) for s in self.__slots__)) 

    MutableEfficientNamedList.__name__ = name 
    return MutableEfficientNamedList 

MyList = namedlist('MyList', 'foo', 'bar', 'baz') 
nl = MyList(1, 2, 3) 
print nl # MyList(1, 2, 3) 
print nl.bar # 2 
print nl[1] # 2 
+0

Или '__slots__ = ['поле {}'. Format (i + 1) для i в xrange (3)]' (полезно, когда есть больше полей) – nneonneo

+0

@nneonneo: Я должен был использовать 'foo',' bar' и 'baz' для имен полей; они были иллюстративными. –

+0

это именно то, что мне нужно, спасибо! – phistakis

2

defaultdict чувствует себя здесь:

from collections import defaultdict 

d = defaultdict(lambda: defaultdict(int)) 

d[3][4] = 10 

Если вы хотите списки фиксированного размера, defaultdict имеет вы покрыли:

d = defaultdict(lambda: [None]*fixed_small_number) 

d[3][4] = 10 
# d[3] is now [None, None, None, None, 10, None, None, ...] 
0

Учитывая, что вы Пример:

for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1) ...]: 
    my_structre[key][k] = v 

Решение действительно будет состоять из defaultdict.

from collections import defaultdict 

d = defaultdict(dict) 
for key, k, v in [('a', 1, 2), ('b', 1, 3), ('a', 2, 1), ('a', 3, 1), ('b', 3, 1)]: 
    d[key][k] = v 

Ответ:

{'a': {1: 2, 2: 1, 3: 1}, 'b': {1: 3, 3: 1}} 

В функции:

def method(iter_of_3_item_iters): 
    d = defaultdict(dict) 
    for (a, b, c) in iter_of_3_item_iters: 
     d[a][b] = c 
    return d 
Смежные вопросы