详尽:
- 字典中的所有键,即使键位于嵌套字典中,也是上一级字典键的值。
排序:
- 这是为了确保按键始终以相同的顺序返回
嵌套是任意深的。首选非递归算法。
level1 = {
'a' : 'aaaa',
'level2_1' : {'b': 'bbbbb', 'level3': {'c': 'cccc', 'd': 'dddddd'} },
'level2_2' : { 'z': 'zzzzzzz' }
}
注意:字典值可以包括列表(可以将字典作为元素),例如
tricky = {'category': [{'content': 'aaaaa'}, {'content': 'bbbbbb'}]}
答案 0 :(得分:6)
def _auxallkeys(aset, adict):
aset.update(adict)
for d in adict.itervalues():
if isinstance(d, dict):
_auxallkeys(aset, d)
def allkeys(adict):
aset = set()
_auxallkeys(aset, adict)
return sorted(aset)
是明显的(递归)解决方案。消除递归:
def allkeys(adict):
aset = set()
pending = [adict]
while pending:
d = pending.pop()
aset.update(d)
for dd in d.itervalues():
if isinstance(dd, dict):
pending.append(dd)
return sorted(aset)
因为处理各种嵌套dicts的 order 对此无关紧要。
编辑:OP评论抱怨说,如果dict没有嵌套,它就不起作用,而是在列表中(我回答它也可能是在一个元组中,一个具有每个实例或每个类的属性的对象[可能是它的基类],一个架子,以及许多其他隐藏房子周围的方法的方法;-)。如果OP将设法通过“嵌套”准确定义他的意思(显然与普通凡人适用于所讨论的词的意义不同),可能更容易帮助他。同时,这是一个涵盖列表(和元组,但不是生成器,许多itertools类的实例,架子等等)的版本;
def allkeys(adict):
aset = set()
pending = [adict]
pendlis = []
def do_seq(seq):
for dd in seq:
if isinstance(dd, dict):
pending.append(dd)
elif isinstance(dd, (list, tuple)):
pendlis.append(dd)
while pending or pendlis:
while pending:
d = pending.pop()
aset.update(d)
do_seq(d.itervalues())
while pendlis:
l = pendlis.pop()
do_seq(l)
return sorted(aset)
答案 1 :(得分:1)
非递归方法现在对我来说并不明显。以下适用于您的原始示例。编辑:它现在将处理dict中列表中的dicts,至少是Alex Martelli回答评论中引用的棘手例子中的一个。
#!/usr/bin/env python
import types
def get_key_list(the_dict, key_list):
for k, v in (the_dict.iteritems()):
key_list.append(k)
if type(v) is types.DictType:
get_key_list(v, key_list)
if type(v) is types.ListType:
for lv in v:
if type(lv) is types.DictType:
get_key_list(lv, key_list)
return
level1 = {
'a' : 'aaaa',
'level2_1' : {'b': 'bbbbb', 'level3': {'c': 'cccc', 'd': 'dddddd'} },
'level2_2' : { 'z': 'zzzzzzz' }
}
tricky = {'category': [{'content': 'aaaaa'}, {'content': 'bbbbbb'}]}
key_list = []
get_key_list(level1, key_list)
key_list.sort()
print key_list
key_list = []
get_key_list(tricky, key_list)
key_list.sort()
print key_list
输出:
['a','b','c','d','level2_1','level2_2','level3','z']
['category','content','content']
答案 2 :(得分:1)
这是一个非递归解决方案,它处理生成器以及列表,元组和dicts,如果一个键出现多次,则添加所有连续的键:
def get_iterator(i):
if hasattr(i, 'next'):
# already an iterator - use it as-is!
return i
elif hasattr(i, '__iter__') and not isinstance(i, basestring):
# an iterable type that isn't a string
return iter(i)
else:
# Can't iterate most other types!
return None
def get_dict_keys(D):
LRtn = []
L = [(D, get_iterator(D))]
while 1:
if not L: break
cur, _iter = L[-1]
if _iter:
# Get the next item
try:
i = _iter.next()
except StopIteration:
del L[-1]
continue
if isinstance(cur, dict):
# Process a dict and all subitems
LRtn.append(i)
_iter = get_iterator(cur[i])
if _iter: L.append((cur[i], _iter))
else:
# Process generators, lists, tuples and all subitems
_iter = get_iterator(i)
if _iter: L.append((i, _iter))
# Sort and return
LRtn.sort()
return LRtn
D = {
'a' : 'aaaa',
'level2_1' : {'b': 'bbbbb', 'level3': {'c': 'cccc', 'd': 'dddddd', 'e': 134, 'f': [{'blah': 553}]} },
'level2_2' : { 'z': 'zzzzzzz' },
'blah2': iter([{'blah3': None}]),
}
print get_dict_keys(D)
编辑:稍微提高速度并缩短代码。
答案 3 :(得分:1)
我也更喜欢递归方法......
#!/usr/bin/env python
def extract_all_keys(structure):
try:
list_of_keys = structure.keys()
for value in structure.values():
add_all_keys_in_value_to_list(value, list_of_keys)
except AttributeError:
list_of_keys = []
return list_of_keys.sort()
def add_all_keys_in_value_to_list(value, list_of_keys):
if isinstance(value, dict):
list_of_keys += extract_all_keys(value)
elif isinstance(value, (list, tuple)):
for element in value:
list_of_keys += extract_all_keys(element)
import unittest
class TestKeys(unittest.TestCase):
def given_a_structure_of(self, structure):
self.structure = structure
def when_keys_are_extracted(self):
self.list_of_keys = extract_all_keys(self.structure)
def testEmptyDict(self):
self.given_a_structure_of({})
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, [])
def testOneElement(self):
self.given_a_structure_of({'a': 'aaaa'})
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['a'])
def testTwoElementsSorted(self):
self.given_a_structure_of({
'z': 'zzzz',
'a': 'aaaa',
})
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['a', 'z'])
def testNestedElements(self):
self.given_a_structure_of({
'a': {'aaaa': 'A',},
'b': {'bbbb': 'B',},
})
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['a', 'aaaa', 'b', 'bbbb'])
def testDoublyNestedElements(self):
self.given_a_structure_of({
'level2': {'aaaa': 'A',
'level3': {'bbbb': 'B'}
}
})
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['aaaa', 'bbbb', 'level2', 'level3'])
def testNestedExampleOnStackOverflow(self):
level1 = {
'a' : 'aaaa',
'level2_1' : {'b': 'bbbbb', 'level3': {'c': 'cccc', 'd': 'dddddd'} },
'level2_2' : { 'z': 'zzzzzzz' }
}
self.given_a_structure_of(level1)
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['a', 'b', 'c', 'd', 'level2_1', 'level2_2', 'level3', 'z'])
def testListExampleOnStackOverflow(self):
tricky = {'category': [{'content': 'aaaaa'}, {'content': 'bbbbbb'}]}
self.given_a_structure_of(tricky)
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['category', 'content', 'content'])
def testTuplesTreatedLikeLists(self):
tricky_tuple = {'category': ({'content': 'aaaaa'}, {'content': 'bbbbbb'})}
self.given_a_structure_of(tricky_tuple)
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, ['category', 'content', 'content'])
def testCanHandleString(self):
self.given_a_structure_of('keys')
self.when_keys_are_extracted()
self.assertEquals(self.list_of_keys, [])
if __name__ == '__main__':
unittest.main()
答案 4 :(得分:0)
我认为使用递归方法更好。 我的代码如下。
level1 = {
'a' : 'aaaa',
'level2_1' : {'b': 'bbbbb', 'level3': {'c': 'cccc', 'd': 'dddddd'} },
'level2_2' : { 'z': 'zzzzzzz' }
}
all_keys=[] # a global list to store all the keys in level1
def depth ( dict ):
for k in dict:
if type(dict[k]) == type(dict): #judge the type of elements in dictionary
depth(dict[k]) # recursive
else:
all_keys.append(k)
depth(level1)
print all_keys