2015-10-03 10 views
1
import string 
from collections import namedtuple 
from collections import defaultdict 
from collections import OrderedDict 

matrix_col = {'11234':0, '21234':2, '31223':0, '46541':0, '83432':1, '56443':2, '63324':0, '94334':0, '72443':1} 
matrix_col = OrderedDict(sorted(matrix_col.items(), key=lambda t: t[0])) 

trans = defaultdict(dict) 
trans['11234']['46541'] = 2 
trans['11234']['21234'] = 1 
trans['11234']['31223'] = 2 
trans['11234']['83432'] = 1 
trans['21234']['31223'] = 2 
trans['21234']['46541'] = 1 
trans['21234']['72443'] = 1 
trans['21234']['83432'] = 1 
trans['56443']['72443'] = 1 
trans['56443']['83432'] = 1 

for u1, v1 in matrix_col.items(): 
    for u2, v2 in matrix_col.items(): 
     for w1 in trans.keys(): 
      for w2, c in trans[u1].items(): 
       if u1 == str(w1) and u2 == str(w2): 
        print u1, u2, c 

Как указано выше, я пытаюсь напечатать элементы транс (defaultdict) на основе отсортированного порядка элементов в matrix_col (OrderedDict) и не может этого сделать. Ниже представлен ожидаемый результат, который я не могу сгенерировать:Python: элементы печати в defaultdict на основе порядка в OrderedDict

11234 11234 0 
11234 21234 1 
11234 31223 2 
11234 46541 2 
11234 56443 0 
11234 63324 0 
11234 72443 0 
11234 83432 1 
11234 94334 0 
21234 11234 0 
21234 21234 0 
21234 31223 2 
21234 46541 1 
21234 56443 0 
21234 63324 0 
21234 72443 1 
21234 83432 1 
21234 94334 0 
31223 11234 0 
31223 21234 0 
31223 31223 0 
31223 46541 0 
31223 56443 0 
31223 63324 0 
31223 72443 0 
31223 83432 0 
31223 94334 0 
... 

Любая помощь приветствуется.

+2

Поскольку вы явно писать Python 2 код, мне нужно указать: 'если u1 в trans.keys(): '- ужасная строка кода. 'trans.keys()' на Python 2 создает новый «список» ключей, поэтому вы делаете довольно большой объект при каждом тестировании, а затем сканируете его линейно для удара, вместо того, чтобы делать «O (1) 'членский тест непосредственно с' if u1 in trans: '. Точно так же большинство применений '.items()' должно быть, вероятно, '.iteritems()' или '.viewitems()' для итерации напрямую, вместо того, чтобы создавать 'list', которые копируют их (plain '.keys()' /'.items() 'полезно, если вы будете мутировать' dict' во время итерации). – ShadowRanger

ответ

0

Нет стандартного способа (что я знаю) для сортировки словаря на основе произвольного сортировки на OrderedDict, но вы всегда можете сортировать по одной и той же вещи. В этом случае просто сортировка по умолчанию должна быть достаточной.

for k, sub_dct in sorted(trans.items()): 
    for sub_k, v in sorted(sub_dct.items()): 
     print k, sub_k, v 

альтернатива, я полагаю, будет обходе OrderedDict дважды и делает поиск против defaultdict.

for k in matrix_col: 
    for sub_k in matrix_col: 
     v = trans.get(k, {}).get(sub_k, 0) 
     print k, sub_k, trans[k][sub_k] 
+0

Спасибо. Хотя, ваш вариант №1 не генерирует результат, который я ищу. Он генерирует только выходные данные с существующими элементами в ** trans **. Ваш вариант №2 дает следующую ошибку: _TypeError: объект 'int' не имеет атрибута '__getitem __'_ –

+0

@JamesDerrick, потому что я сделал простую ошибку. Скорректированный нижний код должен работать. Однако я не понимаю ваш комментарий о опции №1 - если вы пытаетесь сделать что-то другое, кроме генерации вывода из существующих элементов в 'trans', в вашем вопросе неясно. –

+0

Прошу прощения, если я не дал понять: есть OrderedDict, ** matrix_col **. Существует также defaultdict, ** trans **. Мне нужно перебрать все элементы ** trans ** по порядку ** matrix_col ** и распечатать. Если элемент ** matrix_col ** существует в ** trans **, напечатайте его значение c вдоль. Если нет, напечатайте элемент в ** matrix_col ** со значением 0. Пожалуйста, взгляните на ожидаемый результат. Это действительно объяснительно. С вашим кодом вы просто печатаете то, что находится в ** trans **. Можете ли вы также напечатать другие элементы, которые находятся в ** matrix_col **, но не в ** trans **, а их значение равно 0? Спасибо –

0

Я был в состоянии решить эту проблему. Вот оно:

for u1, v1 in matrix_col.items(): 
    for u2, v2 in matrix_col.items(): 
     bastim = True 
     for w1 in trans.keys(): 
      for w2, c in trans[u1].items(): 
       if u1 == str(w1) and u2 == str(w2): 
        print u1, u2, c 
        bastim = False 
     if bastim: 
      print u1, u2, 0 

Спасибо всем.

+0

, но это печатает больше, чем элементы 'trans'. Он включает пары, которые вы никогда не вставляете в 'trans'. – hpaulj

+0

@hpaulj, очевидно, это было предполагаемое поведение. Я тоже этого не понимал. –

0

Эта итерация работы:

for u1 in matrix_col: 
    d = trans[u1] 
    # d may be empty dict 
    for u2 in matrix_col: 
     print u1, u2, d.get(u2, 0) 

Посмотрите на trans до этой итерации:

defaultdict(<type 'dict'>, { 
    '21234': {'31223': 2, '46541': 1, '72443': 1, '83432': 1}, 
    '11234': {'21234': 1, '31223': 2, '46541': 2, '83432': 1}, 
    '56443': {'83432': 1, '72443': 1} 
    }) 

Есть записи для '21234', '11234' и '56443'; Когда итерация использует другой u1, d будет пустой dict, {}. d.get заботится о возврате значимого значения (0) в случае, если u2 нет.

defaultdict добавит записи для каждого ключа, на который вы ссылаетесь, но сначала вам необходимо обратиться к нему. Итерация на trans.keys() не генерирует новые ключи. Ваша начальная итерация сделала то, что вы описали - print the elements of trans (defaultdict).

Ваш логический bastim позаботится об одной и той же проблеме - заполняется 0 с, не в trans.

Если trans является defaultdict из defautdicts, чем итерации может быть немного проще:

def foo(): 
    # the inner dict defaults to 0 
    return defaultdict(int)  
trans = defaultdict(foo) 
for u1 in matrix_col: 
    d = trans[u1] 
    for v1 in matrix_col: 
     print u1,v1, d[v1] 

Это было бы более интересно, если внутренняя ДИКТ собраны значения в списке

def foo(): 
    return defaultdict(list) 
trans = defaultdict(foo) 

и использованные append (и повторяющиеся)

trans['11234']['46541'].append(2) 
trans['11234']['21234'].append(1) 
trans['11234']['31223'].append(2) 
trans['11234']['83432'].append(1) 

trans['11234']['46541'].append(5) 
trans['11234']['21234'].append(3) 
trans['11234']['31223'].append(4) 

производства

11234 11234 [] 
11234 21234 [1, 3] 
11234 31223 [2, 4] 
11234 46541 [2, 5] 
.... 
0

Я расширил свой собственный ответ.Этот код кажется эквивалентным и работает примерно в 3 раза быстрее, хотя и не уверен, что вы ограничены процессором, и он может не работать на python < 2.7 (operator.methodcaller). (Очевидно, лучший вариант производительности просто использовать C или попытаться воспользоваться Numpy матричных операций)

  items=matrix_col.items() 
      import operator 
      for (u1, v1), trans_u1_items in zip(items,map(operator.methodcaller('items'), map(trans.__getitem__,matrix_col))): 
       for u2, v2 in items: 
        bastim = True 
        for w1 in trans: 
         for w2, c in trans_u1_items: 
          if u1 == w1 and u2 == w2: 
           print u1, u2, c 
           bastim = False 
        if bastim: 
         pass 
         print u1, u2, 0