简体   繁体   中英

How can I iterate through sub-elements in a list comprehension?

I have code right now to try to let me sort a dictionary by an arbitrarily deep key (like mongo), but it requires that I hard-code in how many deep the key will be.

#This is the code for inside the function, you need to make a function to receive the  arguments
#and the dictionary. the arguments should be listed in order of layers. It then splits the argument string
#at the "." and assigns to each of the items.From there it should return the "l[]".
#you need to set it up to pass the arguments to these appropriate spots. so the list of dicts goes to
#list and the arguments go to argstring and it should be taken care of from there.


#splitting the argument
argstring="author.age"
arglist = argstring.split(".")

x=(5-len(arglist))#need to set this number to be the most you want to accept
while x>0:
    arglist.append('')
    x-=1

#test list
list = [
{'author' : {'name':'JKRowling','age':47,'bestseller':{'series':'harrypotter','copiessold':12345}}},


{'author' : {'name':'Tolkien','age':81,'bestseller':{'series':'LOTR','copiessold':5678}}},


{'author' : {'name':'GeorgeMartin','age':64,'bestseller':{'series':'Fire&Ice','copiessold':12}}},


{'author' : {'name':'UrsulaLeGuin','age':83,'bestseller':{'series':'EarthSea', 'copiessold':444444}}}
]
l=[]#the list for returning


#determining sort algorythm
l = sorted(list, key=lambda e: e[arglist[0]][arglist[1]])#need add as many of these as necesarry to match the number above
print()

This works, but having to manually specify the arguments in the arglist seems silly. If I needed 5 deep, I'd need to manually specify e 5 times.. Is there a way to use a list comprehension or for loop to automatically include arbitrary element depth?

Use reduce() :

sorted(list, key=lambda e: reduce(lambda m, k: m[k], argslist, e))

reduce() takes a function, an input list and an optional initial value, and re-applies that function to then next element and the return value of the last invocation (starting with the initial value). Thus, it runs m[k0][k1][k2]..[kn] where the successive k values are taken from argslist .

Short demonstration:

>>> e = {'author' : {'name':'JKRowling','age':47,'bestseller':{'series':'harrypotter','copiessold':12345}}}
>>> argslist = ['author', 'age']
>>> reduce(lambda m, k: m[k], argslist, e)
47

There's nothing wrong with using a for loop to traverse the args

>>> e = {'author' : {'name':'JKRowling','age':47,'bestseller':{'series':'harrypotter','copiessold':12345}}}
>>> argslist = ['author', 'age']
>>> result = e
>>> for arg in argslist:
...     result = result[arg]
... 
>>> result
47

This way is really easy to debug, you can put try/except , print , breakpoints etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM