只有 select 个字典键是元组?
Only select dictionary keys that are tuples?
我有一个包含字符串和二元组键的字典。我想将所有 2 元组键从 (x,y) 转换为 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)
但是我无法获得避免非元组键的功能。因为它没有避免非元组键,该函数修复了二元组键但弄乱了非元组键:
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}}}
将 ':'.join(k)
更改为 k if hasattr(k, 'isalpha') else ':'.join(k)
。如果它具有 isalpha
属性,这将使用未更改的对象,这意味着它可能是一个字符串,否则使用冒号连接对象。或者(感谢@Padraic),您可以使用 ':'.join(k) if isinstance(k, tuple) else k
.
您只关心字典和元组,所以只需检查这两个值的递归:
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
受到 的启发,这里有点 "quack-listener":
[':'.join(k), k][k in k]
您可以使用它来代替无条件 ':'.join(k)
。其他想法:
[':'.join(k), k][''.join(k) == k]
[':'.join(k), k][str(k) == k]
不过,我应该说这些令人困惑并且做了不必要的工作。这仅适用于 fun/golfing。 ... 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
我有一个包含字符串和二元组键的字典。我想将所有 2 元组键从 (x,y) 转换为 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)
但是我无法获得避免非元组键的功能。因为它没有避免非元组键,该函数修复了二元组键但弄乱了非元组键:
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}}}
将 ':'.join(k)
更改为 k if hasattr(k, 'isalpha') else ':'.join(k)
。如果它具有 isalpha
属性,这将使用未更改的对象,这意味着它可能是一个字符串,否则使用冒号连接对象。或者(感谢@Padraic),您可以使用 ':'.join(k) if isinstance(k, tuple) else k
.
您只关心字典和元组,所以只需检查这两个值的递归:
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
受到
[':'.join(k), k][k in k]
您可以使用它来代替无条件 ':'.join(k)
。其他想法:
[':'.join(k), k][''.join(k) == k]
[':'.join(k), k][str(k) == k]
不过,我应该说这些令人困惑并且做了不必要的工作。这仅适用于 fun/golfing。 ... 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