Python 迭代字典以创建列表
在名为Python 迭代字典以创建列表,python,mongodb,dictionary,pymongo,aggregation-framework,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" } 我正在尝试创建一个颜色值的有序列表,与不同的有序列表相匹配 例如,如果我有列表[“Johnny”、“Ste
favoriteColors
的MongoDB集合中,我有以下4个字典:
{ "name" : "Johnny", "color" : "green" }
{ "name" : "Steve", "color" : "blue" },
{ "name" : "Ben", "color" : "red" },
{ "name" : "Timmy", "color" : "cyan" }
我正在尝试创建一个颜色值的有序列表,与不同的有序列表相匹配
例如,如果我有列表[“Johnny”、“Steve”、“Ben”、“Johnny”]
,新列表将[“绿色”、“蓝色”、“红色”、“绿色”]
如果我有这个列表,新的列表将是蓝色、蓝色、红色、红色、绿色
使用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"]
如果数据集很小,可以将dict合并成一个新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
方法。答案相应更新。您还可以从当前的dict创建一个新的dict
,其中dict[“名称”]
的每个值都将与dict[“颜色”]
值相关联
例如:新的dict将类似于:
{"Jhonny": "green", "Steve": "blue"}
您可以使用如下示例中的函数,该函数接受多个参数并返回所需的列表(如果输入列表中有任何名称在默认DICS中不存在,它还会附加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']
print(iter_func(my_list, a,b,c,d))
>>> ['blue', 'blue', None, 'red', 'red', 'green', None]
具有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', 'red', 'red', 'green']
print(iter_func(my_list, a,b,c,d))
>>> ['blue', 'blue', None, 'red', 'red', 'green', None]
实际上,我们可以使用聚合框架和客户端处理来高效地完成这项工作
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'}}}
])
因为我们不需要,所以光标包含一个文档,我们可以使用next
检索该文档。事实上,我们可以通过print(list(cursor))
从这里开始,我们需要使用解压文档中的“数据”字段,使用链接输入,并过滤掉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']
您能否创建'name'
->'color'
的映射,然后将该映射与name\u list
一起使用以构建颜色列表?我对mongodb的了解还不够,不知道这是否可以有效地实现,但似乎它可能……不是实现这一点的方法。如果你有一百万个文档与你的查询相匹配呢?OP没有说他的查询像你说的那么大。但是谢谢你的评论。我将尝试改进我的答案。集合对象不可编辑。如果字典是python的,并且几乎没有数据可供迭代,那么这是一种干净的方法。@jcmetz21我看不出这是一种干净的方法db.favoriteColors
是一个集合
对象,未实现迭代器协议,因此此查询将返回我提到的TypeError。如果我将字典放入列表中并在列表中进行迭代,则此查询会起作用。但我同意,如果我们从Mongodbc获取词典,那么这是一种糟糕的做法。你可以用足够多的查询来分享你答案的基准吗?。这似乎很有效。谢谢。这看起来不错,但看起来很复杂。使用聚合框架必须有一种更简单的方法来实现这一点。为什么您需要在“$project”
@jcmetz21下显示所有这些条目?我不认为这很复杂,我将添加解释,如果输出列表中的元素不需要按此精确顺序显示,但不会很简单,那么可能还有另一种方法可以这样做。元素需要按此精确顺序显示,这样看起来很好。谢谢@我的答案不仅看起来不错。这是最好的方法。在MongoDB 3.4中,可能还有另一种方法可以做到这一点。