2016-12-21 33 views
5

は私がfavoriteColorsと呼ばれるMongoDBのコレクションで、次の4つの辞書を持っています。反復処理リストを作成する

たとえば、リストが["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"] 
+2

を使用すると、' '> 'name''' のマッピングを作成することができます返す

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

?これを効率的に行うことができるかどうかを知るためにmongodbについては十分に分かりませんが、それが可能であるように思われます。 – mgilson

答えて

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ので、私たちのカーソルは、私たちが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である要素をフィルタリング。 - color'`その後、color_listを構築するためにname_list` `でそのマッピングを使用

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

十分なクエリで回答のベンチマークを共有できますか?それは効果があるようです。ありがとう。 –

+0

これはうまくいくようですが、とても複雑に見えます。集約フレームワークを使用してこれを行う簡単な方法があるはずです。なぜ "" $ project "' $ project "'の下にすべてのエントリが必要なのですか? –

+0

@ jcmetz21これは複雑ではないと思いますが、出力リストの要素を表示する必要がない場合は説明を追加し、この正確な順序ではありますが、よりシンプルになることはありません* – styvane

0

データセットが小さい場合は、新しいディクテーションにマージできます。

はのpython3では、このような何かを行うことができます。styvane私はCollectionfindメソッドを呼び出すのを忘れて述べたように

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) 

を更新しました。回答はそれに従って更新されました。

+0

コレクションオブジェクトは反復不可能です。これは美しいTypeErrorでひどく失敗するでしょう – styvane

+0

これは、辞書がPythonであり、反復するデータがほとんどない場合、これを行うためのきれいな方法です。 –

+0

@ jcmetz21私はこれが*クリーンな方法*であるかどうか分からなかった。 'db.favoriteColors'は' Collection'オブジェクトであり、イテレータプロトコルを実装していないので、このクエリは前述のようにTypeErrorを返します。 – styvane

0

dict["name"]のすべての値にdict["color"]の値が関連付けられるように、現在のディクテーションから新しいdictを作成することもできます。例えば

:新しい辞書は次のようになります:

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

そして、あなたは多くの引数を受け入れ、それ以下の例のような機能を使用して、目的のリストを返すことができますいずれかが存在する場合(また、それはNoneを追加デフォルトのdictsに存在しない入力リスト)に名前:ここでは

は私の例です:

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] 
+1

これを行う方法ではない。クエリに一致する100万のドキュメントがある場合はどうなりますか? – styvane

+0

OPは、彼の質問があなたの言ったように巨大だとは言わなかった。しかし、あなたのコメントに感謝します。私は私の答えを改善しようとします。 –