1

Первых у меня есть словарь d1, который выглядит следующим образом:Удалить кортежи из списка словаря значения, если первое значение в кортеже = 1

d1 = { 'w' : ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c'], 
      'x' : ['d', 'd', 'd', 'e', 'e'], 
      'y' : ['f', 'f', 'g'], 
      'z' : ['h', 'i']  
    } 

Тогда я рамочный через этот словарь и сделать новый словарь, в котором каждое значении список с двумя элементами: целое число и список. Целое число - это число строк в этом значении в d1. Список содержит кортежи, каждый кортеж, содержащий строку из d1 (в положении 1 кортежа) и количество раз, что строка появилась в d1 (в положении 0 кортежа):

d2 = { 'w' : [10, [(5, 'a'), (3, 'b'), (2, 'c')], 
     'x' : [5, [(3, 'd'), (2, 'e')], 
     'y' : [3, [(2, 'f'), (1, 'g')], 
     'z' : [2, [(1, 'h'), (1, 'i')]  
    } 

Я хочу удалить любая строка, которая появляется только один раз («г», «ч» и «я»), так что в конце концов я хочу:

dFinal = { 'w' : [10, [(5, 'a'), (3, 'b'), (2, 'c')], 
       'x' : [5, [(3, 'd'), (2, 'e')], 
       'y' : [2, [(2, 'f')]  
     } 

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

d = {k:v for k,v in d.items() if len(v) > 1} 

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

Сначала я попытался написать функцию, которая приняла d2 в качестве аргумента, но я не знаю, как ссылаться на позицию 0 каждого кортежа.

Тогда подумал, что было бы намного проще сделать dFinal, используя d1, у которого нет кортежей, вместо того, чтобы пытаться изменить d2.

Если вы могли бы описать чистый способ сделать dFinal от d1 и/или d2, и объяснить процесс мысли, я был бы очень признателен. Оба действительно помогут мне понять, как точно манипулировать списками словарей с пониманием.

Спасибо!

ответ

3

Ну, вы можете использовать объект Counter. Честно говоря, я бы использовал циклы, потому что это, вероятно, будет более эффективным.

In [1]: from collections import Counter 

Edit: Вот как я бы на самом деле это сделать, без постижений:

In [17]: for k,v in d1.items(): 
    ...:  counts = Counter(v) 
    ...:  counts = [t for t in counts.items() if t[1] > 1] 
    ...:  if len(counts) > 0: 
    ...:   dfinal[k] = [sum(c[1] for c in counts), counts] 
    ...: 

In [18]: dfinal 
Out[18]: 
{'w': [10, [('b', 3), ('a', 5), ('c', 2)]], 
'x': [5, [('d', 3), ('e', 2)]], 
'y': [2, [('f', 2)]]} 
+0

Спасибо большое. Однако это не корректирует «целое число» в начале каждого значения. 10, 5 и 3 должны стать 10, 5 и 2. – ddrsee

+0

@ ddrsee пропустил это. Легко исправить. –

+0

Спасибо, миллион. Я прочитаю о Counter и попытаюсь выяснить, что здесь происходит ... – ddrsee

1

Я не думаю, что это хороший стиль, но вы можете сделать это следующим образом:

dFinal = {k: [sum([i for i, c in v[1] if i != 1]), 
       [(i, c) for i, c in v[1] if i != 1]] 
      for k, v in d2.items() 
      if [(i, c) for i, c in v[1] if i != 1]} 

Редактировать: теперь подсчет обновлений. Опять же, если понимание выглядит так, пришло время рефакторинга.

+0

Это не скорректирует количество членов '' y ': [3, [(2,' f ')]] ', хотя, по-видимому, они, вероятно, не нужны. – TemporalWolf

+0

Они необходимы! :-) – ddrsee

+0

Большое спасибо. У вас есть любимый учебник по таким типам понимания (и что такое рефакторинг)? – ddrsee

1

Это

from collections import Counter 

d2 = {k: [len(v), sorted(Counter(v).items())] for k, v in d1.items()} 

dFinal = {k: [v1, [(y, x) for x, y in v2 if y > 1]] for k, (v1, v2) in d2.items()} 

Мои d2 и dFinal немного отличается от вашего.Это мой d2

{'w': [10, [('a', 5), ('b', 3), ('c', 2)]], 
'x': [5, [('d', 3), ('e', 2)]], 
'y': [3, [('f', 2), ('g', 1)]], 
'z': [2, [('h', 1), ('i', 1)]]} 

это мой dFinal

{'w': [10, [(5, 'a'), (3, 'b'), (2, 'c')]], 
'x': [5, [(3, 'd'), (2, 'e')]], 
'y': [3, [(2, 'f')]], 
'z': [2, []]} 

но вы можете легко исправить это сами.

btw: Я бы использовал функции, чтобы облегчить понимание словаря и списка. Сейчас он не читается.

+0

Зачем вы это делаете: 'dict (Counter (v)). Items())' ??? –

+0

Чтобы преобразовать '['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c']' в это '[ ('a', 5), ('b', 3), ('c', 2)] '. – Elmex80s

+1

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

1

Другой вариант: медленнее, но легче следовать:

def has_dupe(lst): 
    return any([x[0] > 1 for x in lst[1]]) 

def reduce_list(lst): 
    result = [(x, y) for (x, y) in lst[1] if x > 1] 
    return [sum([x for (x, y) in result]), result] 

d = {key: reduce_list(value) for key, value in d2.items() if has_dupe(value)} 
Смежные вопросы