2015-06-03 57 views
2

我有一個字典與字符串和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

變化':'.join(k)k if hasattr(k, 'isalpha') else ':'.join(k)。如果它具有屬性isalpha,這意味着它可能是一個字符串,或者用冒號連接對象,否則這將使用未改變的對象。或者(謝謝,@Padraic),您可以使用':'.join(k) if isinstance(k, tuple) else k

+1

我想餵鴨類型,但。 – TigerhawkT3

+0

我不遵循,如果hasattr(k,'isalpha')'做了issinstance(k,str)'不會呢? –

+0

我不是在問是否是鴨子,而是在聆聽庸醫。 :) – TigerhawkT3

1

你只關心類型的字典和元組所以只檢查這兩個遞歸的值:

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}}} 

此修改,我認爲是實際的目標原來字典。

如果你希望它爲所有iterables工作,除了一個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 
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 
+0

爲什麼downvote?它有效,我警告它的壞處,我認爲這是教育/有趣的。 –