从字典中删除空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的两倍。