只选择作为元组的字典键?

时间:2015-06-03 23:35:44

标签: python dictionary tuples

我有一个包含字符串和2元组键的字典。我想将(x,y)中的所有2元组键转换为x:y的字符串。这是我的数据:

In [4]:

data = {('category1', 'category2'): {'numeric_float1': {('Green', 'Car'): 0.51376354561039017,('Red', 'Plane'): 0.42304110216698415,('Yellow', 'Boat'): 0.56792298947973241}}}
data
Out[4]:
{('category1',
  'category2'): {'numeric_float1': {('Green', 'Car'): 0.5137635456103902,
   ('Red', 'Plane'): 0.42304110216698415,
   ('Yellow', 'Boat'): 0.5679229894797324}}}

但是,这是我想要的字典输出:

{'category1:category2': 
    {'numeric_float1': 
        {'Green:Car': 0.5137635456103902,
         'Red:Plane': 0.42304110216698415,
         'Yellow:Boat': 0.5679229894797324}}}

我更改了a previous SO answer中的代码,以创建一个更改所有键的递归函数。

In [5]:

def convert_keys_to_string(dictionary):
    if not isinstance(dictionary, dict):
        return dictionary
    return dict((':'.join(k), convert_keys_to_string(v)) for k, v in dictionary.items())

convert_keys_to_string(data)

但是我无法获得避免非元组密钥的功能。因为它不能避免使用非元组键,所以该函数修复了2元组键,但却弄乱了非元组键:

Out[5]:
{'category1:category2': {'n:u:m:e:r:i:c:_:f:l:o:a:t:1': {'Green:Car': 0.5137635456103902,
   'Red:Plane': 0.42304110216698415,
   'Yellow:Boat': 0.5679229894797324}}}

3 个答案:

答案 0 :(得分:3)

':'.join(k)更改为k if hasattr(k, 'isalpha') else ':'.join(k)。如果它具有属性isalpha,这将使用未更改的对象,这意味着它可能是一个字符串,否则用冒号连接对象。或者(感谢@Padraic),您可以使用':'.join(k) if isinstance(k, tuple) else k

答案 1 :(得分:1)

您只关心dicts和元组,所以只需检查值的递归:

def rec(d):
    for k,v in d.items():
        if isinstance(v, dict):
            rec(v)
        if isinstance(k, tuple):
            del d[k]
            d[":".join(k)] = v

rec(data)

from pprint import pprint as pp
pp(data)

输出:

{'category1:category2': {'numeric_float1': {'Green:Car': 0.5137635456103902,
                                            'Red:Plane': 0.42304110216698415,
                                            'Yellow:Boat': 0.5679229894797324}}}

这修改了我认为是实际目标的原始字典。

如果你想让它适用于除str:

之外的所有迭代
from collections import Iterable
def rec(d):
    for k, v in d.items():
        if isinstance(v, dict):
            rec(v)
        if isinstance(k, Iterable) and not isinstance(k,  str):
            del d[k]
            d[":".join(k)] = v

答案 2 :(得分:1)

@TigerhawkT3's answer的启发,这里有点“庸医听”:

[':'.join(k), k][k in k]

您可以使用它代替无条件的':'.join(k)。其他想法:

[':'.join(k), k][''.join(k) == k]
[':'.join(k), k][str(k) == k]
但是,我应该说这些令人困惑,并且做了不必要的工作。这只是为了娱乐/打高尔夫球。 ... if isinstance(...) else ...是正确的方法。虽然k in k实际上可能比isinstance(k, str)更快:

>>> timeit('k in k',             "k = 'numeric_float1'")
0.222242249806186
>>> timeit('isinstance(k, str)', "k = 'numeric_float1'")
0.3160444680784167

>>> timeit('k in k',             "k = ('Yellow', 'Boat')")
0.21133306092963267
>>> timeit('isinstance(k, str)', "k = ('Yellow', 'Boat')")
0.5903861610393051