从字典中删除空string的有效方法

我有一个字典,并希望删除所有的空值string的键。

metadata = {u'Composite:PreviewImage': u'(Binary data 101973 bytes)', u'EXIF:CFAPattern2': u''} 

做这个的最好方式是什么?

 dict((k, v) for k, v in metadata.iteritems() if v) 

请注意,您的所有密钥都有值。 只是其中一些值是空string。 没有价值的字典中没有这样的关键字; 如果它没有价值,那就不会在字典里。

它可以比BrenBarn的解决scheme更短(我认为更具可读性)

 {k: v for k, v in metadata.items() if v} 

用Python 2.7.3testing。

如果你真的需要修改原来的字典:

 empty_keys = [k for k,v in metadata.iteritems() if not v] for k in empty_keys: del metadata[k] 

请注意,我们必须制作空键的列表,因为我们不能在迭代时修改字典(正如您可能已经注意到的那样)。 尽pipe如此,除了创build一个全新的字典,这种方法的成本更低(记忆方面),除非有很多空值的条目。

如果你想要一个function齐全但简洁的方法来处理经常嵌套的真实世界的数据结构,甚至可以包含循环,我build议从boltons实用程序包中查看重映射实用程序 。

pip install boltons或者将iterutils.py复制到你的项目中,只需要:

 from boltons.iterutils import remap drop_falsey = lambda path, key, value: bool(value) clean = remap(metadata, visit=drop_falsey) 

这个页面有更多的例子,包括从Github的API中处理更多的对象。

它是纯Python,因此它在任何地方都能正常工作,并且已经在Python 2.7和3.3+中进行了全面testing。 最重要的是,我写了这样的案例,所以如果你发现一个案件,它不能处理,你可以bug我修复它在这里 。

BrenBarn的解决scheme是理想的( pythonic ,我可能会添加)。 这是另一个(fp)解决scheme,但是:

 from operator import itemgetter dict(filter(itemgetter(1), metadata.items())) 

基于瑞安的解决scheme ,如果你也有列表和嵌套字典:

 def remove_empty_from_dict(d): if type(d) is dict: return dict((k, remove_empty_from_dict(v)) for k, v in d.iteritems() if v and remove_empty_from_dict(v)) elif type(d) is list: return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)] else: return d 

如果你有一个嵌套的字典,并且你希望这个字典甚至可以用于空的子元素,你可以使用BrenBarn的build议的recursion变体:

 def scrub_dict(d): if type(d) is dict: return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v)) else: return d 

以patriciasz和nneonneo的答案为基础 ,并考虑到你可能想要删除只包含某些falsy的东西(例如'' )而不是其他的东西(比如0 )的可能性,或者你甚至想要包含一些真实的东西(如'SPAM' ),那么你可以做一个非常具体的hitlist:

 unwanted = ['', u'', None, False, [], 'SPAM'] 

不幸的是,这不起作用,因为例如0 in unwanted评估为True 。 我们需要区分0和其他的falsy事物,所以我们必须使用的is

 any([0 is i for i in unwanted]) 

…评估为False

现在用它来del不需要的东西:

 unwanted_keys = [k for k, v in metadata.items() if any([v is i for i in unwanted])] for k in unwanted_keys: del metadata[k] 

如果你想要一个新的字典,而不是修改metadata

 newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])} 

快速回答(TL; DR)

Example01

 ### example01 ------------------- mydict = { "alpha":0, "bravo":"0", "charlie":"three", "delta":[], "echo":False, "foxy":"False", "golf":"", "hotel":" ", } newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(vdata) ]) print newdict ### result01 ------------------- result01 =''' {'foxy': 'False', 'charlie': 'three', 'bravo': '0'} ''' 

详细的答案

问题

  • 上下文: Python 2.x
  • scheme:开发人员希望修改字典以排除空白值
    • 又名从字典中删除空值
    • 又名删除键与空白值
    • 又名过滤词典,用于每个键值对上的非空值

  • example01使用python list-comprehension语法和简单的条件来删除“空”值

陷阱

  • example01仅在原始字典的副本上运行(不会在原地进行修改)
  • example01可能会产生意想不到的结果,具体取决于开发人员通过“空”
    • 开发人员是否意味着保留那些虚伪的价值 ?
    • 如果字典中的值不能作为string,开发人员可能会意外丢失数据。
    • result01显示从原始集合中只保留了三​​个键值对

替代的例子

  • example02有助于处理潜在的隐患
  • 该方法是通过改变条件来使用“空”的更精确的定义。
  • 这里我们只想过滤出空白string的值。
  • 这里我们也使用.strip()过滤掉只包含空格的值。

Example02

 ### example02 ------------------- mydict = { "alpha":0, "bravo":"0", "charlie":"three", "delta":[], "echo":False, "foxy":"False", "golf":"", "hotel":" ", } newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(str(vdata).strip()) ]) print newdict ### result02 ------------------- result02 =''' {'charlie': 'three', 'echo': False, 'foxy': 'False', 'delta': [], 'bravo': '0', 'alpha': 0 } ''' 

也可以看看

  • 列表理解
  • falsy
  • 检查空string
  • 修改原始字典到位
  • 词典理解
  • 检查空string的缺陷

对于python 3

 dict((k, v) for k, v in metadata.items() if v) 

一些基准:

1.列表理解重新字典

 In [7]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None ...: dic = {k: v for k, v in dic.items() if v is not None} 1000000 loops, best of 7: 375 ns per loop 

2.列表理解使用dict()重新创build字典

 In [8]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None ...: dic = dict((k, v) for k, v in dic.items() if v is not None) 1000000 loops, best of 7: 681 ns per loop 

3.如果v是None,则循环并删除键

 In [10]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None ...: for k, v in dic.items(): ...: if v is None: ...: del dic[k] ...: 10000000 loops, best of 7: 160 ns per loop 

所以循环和删除在160ns是最快的,列表理解是在〜375ns的一半缓慢,并且对dict()的调用再慢一半〜680ns。

将3封装到一个函数中会使其重新回到约275ns。 对我来说,PyPy的速度是neet python的两倍。