迭代字典以创建列表

时间:2016-12-21 21:20:19

标签: python mongodb dictionary pymongo aggregation-framework

我在名为favoriteColors的MongoDB集合中有以下4个词典:

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

我试图创建一个与不同有序列表匹配的ORDERED颜色值列表。

例如,如果我有列表["Johnny", "Steve", "Ben", "Johnny"],则新列表将["green", "blue", "red", "green"]

如果我有列表["Steve", "Steve", "Ben", "Ben", "Johnny"],则新列表将为["blue", "blue", "red", "red", "green"]

使用Python和/或PyMongo这是一个很好的方法。这是我到目前为止所做的,但它没有认识到重复。

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"]

3 个答案:

答案 0 :(得分:1)

实际上,我们可以使用聚合框架和客户端处理来有效地执行此操作。

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'}}}
])

因为我们$group是None,我们的光标包含一个文档,我们可以使用next来检索它。事实上,我们可以通过print(list(cursor))

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

从这里,我们需要解包"数据"使用zip的文档中的字段,使用chain.from_iterable对输入进行链接,并过滤掉None的元素。

from itertools import chain

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

返回:

>>> result
['green', 'blue', 'red', 'green']

答案 1 :(得分:0)

如果数据集很小,您可以将dicts合并为一个新的dict。

在python3中你可以这样做:

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)

更新

正如styvane所说,我忘了在find上调用Collection方法。答案相应更新。

答案 2 :(得分:0)

您还可以根据当前的代码创建新的dict,其中dict["name"]的每个值都与dict["color"]值相关联。

例如:新词典将如下:

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

你可以使用类似下面例子的函数来接受许多参数并返回所需的列表(如果输入列表中有任何名称在默认值中不存在,它还会附加None) :

以下是我的例子:

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]

输出:

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

None值的示例:

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]

输出:

print(iter_func(my_list, a,b,c,d))
>>> ['blue', 'blue', None, 'red', 'red', 'green', None]
相关问题