0

For example, here I have:

doc = { 'A':1, 'B':1, 'C':{'C-A':2, 'C-B':{'C-B-A':3}}

then I define a func like this:

def get(doc, *args):
    if(len(args) == 1):
        return doc[args[0]]
    if(len(args) == 2):
        return doc[args[0]][args[1]]
    if(len(args) == 3):
        return doc[args[0]][args[1]][args[2]]

so I can get values like this:

get(doc,'A') //return 1
get(doc,'C','C-A') //return 2
get(doc,'C','C-B') //return {'C-B-A':3}
get(doc,'C','C-B','C-B-A') //return 3

Now my question is, if doc has any depth, how to rewrite func get?

4

2 回答 2

2

使用递归:

def get(doc, *args):
    return get(doc[args[0]], *args[1:]) if args else doc

或者,如果出于某种原因您更喜欢迭代地进行

def get(doc, *args):
   for arg in args:
      doc = doc[arg]
   return doc

这与@Bakuriu 的答案非常接近。

于 2013-09-26T09:47:31.037 回答
2

你可以使用reduce

In [17]: doc = { 'A':1, 'B':1, 'C':{'C-A':2, 'C-B':{'C-B-A':3}}}
    ...: 
    ...: def get(doc, *args):
    ...:     return reduce(dict.get, args, doc)

In [18]: get(doc, 'A')
Out[18]: 1

In [19]: get(doc, 'C', 'C-A')
Out[19]: 2

In [20]: get(doc, 'C', 'C-B', 'C-B-A')
Out[20]: 3

你可以这样想reduce

def reduce(function, arguments, initializer):
    a = initializer
    for b in arguments:
        a = function(a, b)
    return a

即它在给定的参数上“累积”调用二进制函数的值。在您的情况下,首先adoc. 然后,它变成 的结果doc[arguments[0]]。如果arguments长度为一,则迭代停止并返回结果,否则它是子字典之一,并且在下一次迭代中,循环将从该子字典中获取一个值。


请注意,使用递归意味着将深度限制为sys.getrecursionlimit(),通常约为 1000,并且它会慢得多,因为您至少要执行两次函数调用来检索值:

In [84]: def get(doc, *args):
    ...:     return reduce(dict.get, args, doc)

In [85]: def get2(doc, *args):
    ...:     return get2(doc[args[0]], *args[1:]) if args else doc

In [86]: %timeit get(doc, 'C', 'C-B', 'C-B-A')
1000000 loops, best of 3: 621 ns per loop

In [87]: %timeit get2(doc, 'C', 'C-B', 'C-B-A')
1000000 loops, best of 3: 1.04 us per loop

In [88]: d = make_dict(depth=350) 

In [89]: %timeit get(d, *range(350))
10000 loops, best of 3: 38.9 us per loop

In [90]: %timeit get2(d, *range(350))
1000 loops, best of 3: 973 us per loop

这使用了一个浅字典。如果您尝试使用深度更大的 dict,则与功能解决方案相比,递归解决方案将变得越来越慢。

于 2013-09-26T09:42:34.457 回答