Dictionary iteration to create a list

I have 4 dictionaries in the MongoDB collection called favoriteColors :

 { "name" : "Johnny", "color" : "green" } { "name" : "Steve", "color" : "blue" }, { "name" : "Ben", "color" : "red" }, { "name" : "Timmy", "color" : "cyan" } 

I am trying to create a list of ORDERED color values โ€‹โ€‹corresponding to another ordered list.

For example, if I have a list ["Johnny", "Steve", "Ben", "Johnny"] , the new list will be ["green", "blue", "red", "green"] .

And if I have a list ["Steve", "Steve", "Ben", "Ben", "Johnny"] , the new list will be ["blue", "blue", "red", "red", "green"] .

What a good way to do this using Python and / or PyMongo. This is what I have so far, but it does not recognize duplicates.

 name_list = ["Steve", "Steve", "Ben", "Ben", "Johnny"] color_list = [] for document in db.favoriteColors.aggregate([ {"$match": {"name": {"$in": name_list }}}, {"$project": {"color": 1}} ]): for k, v in document.iteritems(): color_list.append(v) print color_list # ["blue", "red", "green"] 
+5
source share
3 answers

In fact, we can use the aggregation structure with processing on the client side to effectively do this.

 import pymongo client = pymongo.MongoClient() db = client.test # Or whatever is your database favoriteColors = db.favoriteColors first_list = ['Johnny', 'Steve', 'Ben', 'Johnny'] cursor = favoriteColors.aggregate([ {'$match': {'name': {'$in': first_list}}}, {'$project': {'part': {'$map': { 'input': first_list, 'as': 'inp', 'in': { '$cond': [ {'$eq': [ '$$inp', '$name']}, '$color', None ] } }}}}, {'$group': {'_id': None, 'data': {'$push': '$part'}}} ]) 

Since we are nothing to $group , our pointer contains one document that we can get with next . In fact, we can verify that with print(list(cursor))

 >>> import pprint >>> pprint.pprint(list(cursor)) [{'_id': None, 'data': [['green', None, None, 'green'], [None, 'blue', None, None], [None, None, 'red', None]]}] 

Here we need to unzip the "data" field in the document using zip , connect the inputs using chain.from_iterable and filter out the None elements.

 from itertools import chain result = [item for item in chain.from_iterable(zip(*next(cursor)['data'])) if item is not None] 

What returns:

 >>> result ['green', 'blue', 'red', 'green'] 
+1
source

If the data set is small, you can combine the dicts into one new dict.

In python3 you can do something like this:

 names = ["Steve", "Steve", "Ben", "Ben", "Johnny"] favorites = {d["name"]: d["color"] for d in db.favoriteColors.find()} colors = [favorites[name] for name in names] print(colors) 

Update

As stevan said, I forgot to call the find method on Collection . Accordingly, the response is updated.

0
source

You can also create a new dict from your current dicts in which each dict["name"] value will be associated with a dict["color"] value.

For example: the new dict will look like this:

 {"Jhonny": "green", "Steve": "blue"} 

And you can use a function similar to the example below, which takes a lot of arguments and returns the desired list (In addition, it adds None if the input list has any name that is not in the default files):

Here is my example:

 a = { "name" : "Johnny", "color" : "green" } b = { "name" : "Steve", "color" : "blue" } c = { "name" : "Ben", "color" : "red" } d = { "name" : "Timmy", "color" : "cyan" } my_list = ["Steve", "Steve", "Ben", "Ben", "Johnny"] def iter_func(my_list = list, *args): ne = {k["name"]:k["color"] for k in args} return [ne[k] if k in ne.keys() else None for k in my_list] 

Output:

 print(iter_func(my_list, a,b,c,d)) >>> ['blue', 'blue', 'red', 'red', 'green'] 

Example with None values:

 a = { "name" : "Johnny", "color" : "green" } b = { "name" : "Steve", "color" : "blue" } c = { "name" : "Ben", "color" : "red" } d = { "name" : "Timmy", "color" : "cyan" } my_list = ["Steve", "Steve", "Alex", "Ben", "Ben", "Johnny", "Mark"] def iter_func(my_list = list, *args): ne = {k["name"]:k["color"] for k in args} return [ne[k] if k in ne.keys() else None for k in my_list] 

Output:

 print(iter_func(my_list, a,b,c,d)) >>> ['blue', 'blue', None, 'red', 'red', 'green', None] 
0
source

Source: https://habr.com/ru/post/1261670/


All Articles