2016-04-01 2 views
0

У меня есть dict, скажем, например, этоесть лучший способ очистить диктофон?

data={k:k for k in range(20)} 

я сделать некоторые операции над значениями data и некоторые из ванной в качестве 0, например, это

for k,v in data.items(): 
    data[k] %= 2 

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

def clean(data): 
    while True: 
     try: 
      for k,v in data.items(): 
       if not v: 
        del data[k] 
      return 
     except RuntimeError: 
      pass 

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

EDIT

это похоже на мой предназначению

class MapDict(dict): 

    def __repr__(self): 
     return '{}({})'.format(self.__class__.__qualname__, super().__repr__()) 

    def map(self,func,*argv): 
     '''applicate func to every value in this MapDict''' 
     for k,v in self.items(): 
      self[k] = func(v,*argv) 
     self.clean() 

    def clean(self): 
     while True: 
      try: 
       for k,v in self.items(): 
        if not v: 
         del self[k] 
       return 
      except RuntimeError: 
       pass 


>>> data=MapDict((k,k) for k in range(20)) 
>>> data 
MapDict({0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19}) 
>>> from operator import add, mod 
>>> data.map(mod,2) 
>>> data 
MapDict({1: 1, 3: 1, 5: 1, 7: 1, 9: 1, 11: 1, 13: 1, 15: 1, 17: 1, 19: 1}) 
>>> data.map(add,10) 
>>> data 
MapDict({1: 11, 3: 11, 5: 11, 7: 11, 9: 11, 11: 11, 13: 11, 15: 11, 17: 11, 19: 11}) 
>>> 

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

Так есть лучший способ сделать это чистым? сохраняя при этом эффективность памяти? и в наименьшей сумме поездки?

+1

См http://stackoverflow.com/questions/9023078/custom-dict-that-allows-delete-during-iteration – Stuart

+0

Вы, вероятно, не хотите писать подклассы так, я хотел бы посмотреть в к одной из функциональных программных библиотек (toolz, funcy и т. д.), которые обеспечивают отличные функции потоковой передачи для большинства этих функций. – tacaswell

+0

@tcaswell, возможно, карта является плохим именем для этого метода, но это именно то, что я хочу, выполняю операцию на месте, но 'toolz' отлично смотрится для операций, которые я делаю, которые не на месте – Copperfield

ответ

1

Есть жесткое требование, чтобы сделать это на месте, если нет:

def clean(data): 
    return {k: v for k, v in data.items() if v} 

если так

def clean(data): 
    remove_keys = tuple(k for k, v in data.items() if not v) 
    for k in remove_keys: 
     del data[k] 
+0

да, я хотите, чтобы память была эффективной, поэтому копирование элементов - это нет. – Copperfield

+1

. Регламентация не создает копию элементов, просто делает другую ссылку на базовые объекты. – tacaswell

+0

@Copperfield, за исключением того, что я бы использовал кортеж вместо списка, это должно быть лучшее, что вы можете получить. Вторая реализация выполняет только копирование (ссылка на/значение), если условие («не v» в этом случае) истинно. – SleepProgger

2

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

for k in list(data): 
    v = data[k] 
    if not v: 
     del data[k] 
+0

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

+2

@Copperfield. Вы не можете безопасно изменять последовательность, которую вы итерируете. Вы * должны * перебирать копию ключей. – chepner

2

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

keys_to_del = [] 
for k, v in data.items(): 
    data[k] %= 2 
    if data[k] == 0: 
     keys_to_del.append(k) 
for k in keys_to_del: 
    del data[k] 
+0

Вы можете немного сократить его: для k в кортеже (ik для ik, iv в data.items(), если iv% 2 ​​== 0): ... Использовать iteritems для python 2.7 – SleepProgger

+0

@SleepProgger Нет, это wouldn Не меняйте значения. И зачем использовать кортеж? – Stuart

+0

С заменой «del data [k]» мой код будет делать то же, что и ваш. Создание кортежей должно быть немного быстрее. – SleepProgger

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