关于python:从dict中删除带有空字符串的键的有效方法

Efficient way to remove keys with empty strings from a dict

我有一个dict,想删除所有有空值字符串的键。

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

最好的方法是什么?


Python 2.x。 </P >

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

Python 2.7×3。 </P >

1
{k: v for k, v in metadata.items() if v is not None}

注意你的钥匙,是所有有价值的。它的正是那一些这些值的字符串是空的。没有这样的东西作为一个关键的字典中没有值;如果它不有一个值,它不可能要问的字典。 </P >


它可以brenbarn山羊甚至比短的溶液(和更多的我想readable) </P >

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

2.7.3用Python测试。 </P >


如果你真的要修改的原始字典: </P >

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

注意,我们要做一个狡猾的空的钥匙,因为我们不能修改字典随迭代通(作为你的计算机可能有noticed)。这是无聊的扩张(记忆之比(A)创造全新的字典,但是,除非这是一个很多entries与空值。 </P >


如果你想要A,功能齐全,succinct方法对真实世界的行为,这是经常的数据结构和套式,甚至可以包含的周期,在recommend看着《remap型从博尔顿型包。 </P >

售后copying iterutils.py pip install boltons或为你的项目做: </P >

1
2
3
4
from boltons.iterutils import remap

drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)

本页有许多更多的例子,包括所有的工作与多larger对象从GitHub的API。 </P >

它的纯Python,所以它everywhere冰厂,全面测试和Python 2.7分和3.3 +。所有的野兽,在它的wrote exactly案件,所以呢,如果你找到一个实例的计算机不对付,你可以修复它的错误我到这里吧。 </P >


基于瑞安的溶液,如果你也有和套式词典列表: </P >

方法2:Python </P >

1
2
3
4
5
6
7
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

因为Python 3: </P >

1
2
3
4
5
6
7
def remove_empty_from_dict(d):
    if type(d) is dict:
        return dict((k, remove_empty_from_dict(v)) for k, v in d.items() 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的溶液和冰的理想语言,可能会增加)。这里的另一个冰(FP)溶液,然而: </P >

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


如果你有一套式词典,和你想要的文件到工作,甚至为空的子元素,你可以使用递归brenbarn变型A学院的建议: </P >

1
2
3
4
5
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),我想你也许甚至包括一些东西(例如truthy 'SPAM'),然后你可以做一个高度特异性的名单: </P >

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

不幸的是,这不quite因为工作的关系,例如0 in unwantedevaluates到True。我们要discriminate之间falsy 0和其他的东西,所以我们要用is: </P >

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

...evaluates到False。 </P >

现在使用它的unwanted del的事情: </P >

1
2
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]

如果你想一个新的字典,而不是大学modifying metadata进入坟墓 </P >

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


快速应答(TL;博士) example01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
### 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'}
'''

详细的回答 问题

  • 目的:2.x Python
  • 场景:开发商的意愿修改A blank values to排除词典
    • 又名remove空值从一本字典
    • 又名delete键with blank values
    • 又名滤波器字典的非空白值在每一对密钥值

溶液

  • example01使用Python列表理解语法和简单的条件去解除"空"的价值观

pitfalls

  • example01只operates在线杂志的一份正本(美国能源部词典标注修改输入的地方)
  • example01可能产生意想不到的结果depending通什么开发商均值村"空"
    • 美国能源部的开发商均对保持falsy值,是吗?
    • 如果值是在字典中注释的字符串中确保的是,开发商可能会有意想不到的数据槽。
    • result01演那只三关键值是保持对从原集

另以

  • example02 helps pitfalls交易与潜力
  • 冰的方法对使用一个更精确的定义,"空"村的变化的条件。
  • 在这里我们只想滤波器超时值是评价到空白的字符串。
  • 让我们也使用.strip()对滤波器的超时值是只读的consist大学的空白。

example02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
### 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 ='''
{'alpha': 0,
  'bravo': '0',
  'charlie': 'three',
  'delta': [],
  'echo': False,
  'foxy': 'False'
  }
'''

也见

  • 战略的理解
  • falsy
  • 检查字符串为空
  • 在原来的地方modifying词典
  • 字典的理解
  • pitfalls部检查为空字符串

因为Python 3 </P >

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

我阅读了这篇文章中的所有回复,有些还提到了这篇文章:用递归函数删除嵌套字典中的空dict

我最初在这里使用的解决方案非常有效:

尝试1:太热(无法执行或证明未来):

1
2
3
4
5
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

但在python 2.7世界中出现了一些性能和兼容性问题:

  • isinstance代替type
  • 将列表组件展开到for循环以提高效率
  • 使用python3安全的items,而不是iteritems
  • 尝试2:太冷(缺少记忆):

    1
    2
    3
    4
    5
    6
    7
    8
    def scrub_dict(d):
        new_dict = {}
        for k, v in d.items():
            if isinstance(v,dict):
                v = scrub_dict(v)
            if not v in (u'', None, {}):
                new_dict[k] = v
        return new_dict

    呸!这不是递归的,完全不是memoizant。

    尝试3:刚刚好(目前为止):

    1
    2
    3
    4
    5
    6
    7
    8
    def scrub_dict(d):
        new_dict = {}
        for k, v in d.items():
            if isinstance(v,dict):
                v = scrub_dict(v)
            if not v in (u'', None, {}):
                new_dict[k] = v
        return new_dict


    上面提到的一些方法忽略是否存在任何整数,并且浮点值为0&0.0

    如果有人想避免上述情况,可以使用以下代码(从嵌套字典和嵌套列表中删除空字符串和无值):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def remove_empty_from_dict(d):
        if type(d) is dict:
            _temp = {}
            for k,v in d.items():
                if v == None or v =="":
                    pass
                elif type(v) is int or type(v) is float:
                    _temp[k] = remove_empty_from_dict(v)
                elif (v or remove_empty_from_dict(v)):
                    _temp[k] = remove_empty_from_dict(v)
            return _temp
        elif type(d) is list:
            return [remove_empty_from_dict(v) for v in d if( (str(v).strip() or str(remove_empty_from_dict(v)).strip()) and (v != None or remove_empty_from_dict(v) != None))]
        else:
            return d

    如果您使用的是pandas,这里有一个选项:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import pandas as pd

    d = dict.fromkeys(['a', 'b', 'c', 'd'])
    d['b'] = 'not null'
    d['c'] = ''  # empty string

    print(d)

    # convert `dict` to `Series` and replace any blank strings with `None`;
    # use the `.dropna()` method and
    # then convert back to a `dict`
    d_ = pd.Series(d).replace('', None).dropna().to_dict()

    print(d_)

    另一种方法是使用字典理解。这应该与2.7+兼容。

    1
    2
    3
    4
    5
    result = {
        key: value for key, value in
        {"foo":"bar","lorem": None}.items()
        if value
    }

    一些基准:1。列表理解重新创建dict

    1
    2
    3
    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()重新创建dict

    1
    2
    3
    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

    三。如果v为无,则循环并删除键

    1
    2
    3
    4
    5
    6
    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

    所以loop和delete是最快的,在160ns时,列表理解的速度是在375ns时的一半,调用dict()的速度是在680ns时的一半。

    将3包装成一个函数,使它再次回到275ns左右。对我来说,pypy的速度是neet python的两倍。