2009-09-24 19 views
13

はのは、私は次のような異なる特性を有する1つのまたは2つ以上のダースのオブジェクトを持っていないとしましょうLocation = "Boston"、またはType = "Primary"のすべてのオブジェクトを呼び出します。古典的なデータベースクエリタイプのもの。小さなテーブルのPython?私のことができるようにしたい</p> <p>UID、名前、値、カラー、タイプ、場所</p> <p>:

ほとんどのテーブルソリューション(pytables、* sql)は、このような小さなデータセットの場合、実際には過剰です。すべてのオブジェクトを繰り返し処理し、データ列ごとに個別の辞書を作成するだけです(新しいオブジェクトを追加するときに辞書に値を追加する)。

これは、このようなdicts作成します。

{ 'ボストン':[234、654、234]、 'シカゴ':[324、765、342]} - これらの3桁のエントリは、UIDのようなものを表し。

ご覧のとおり、これを照会するのはちょっとした痛みです。

代替手段はありますか?

答えて

14

私はPythonの組み込みのsetsを使用するのが大好きです。

users = { 
    1: dict(Name="Mr. Foo", Location="Boston", Type="Secondary"), 
    2: dict(Name="Mr. Bar", Location="New York", Type="Primary"), 
    3: dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"), 
    #... 
} 

をあなたはこのようなWHERE ... OR ...クエリを行うことができます:あなたは、このデータを持っていた場合は場所= 'ボストン' ORタイプ= 'プライマリ' の例

set1 = set(u for u in users if users[u]['Location'] == 'Boston') 
set2 = set(u for u in users if users[u]['Type'] == 'Primary') 
result = set1.union(set2) 

か1つの式で

result = set(u for u in users if users[u]['Location'] == 'Boston' 
           or users[u]['Type'] == 'Primary') 

の関数を使用することもできます10を使用して、データのかなり効率的なクエリを作成します。あなたはGROUP BY cityに似た何かをしたい場合例:

cities = ('Boston', 'New York', 'Chicago') 
cities_users = dict(map(lambda city: (city, ifilter(lambda u: users[u]['Location'] == city, users)), cities)) 

また、物事をスピードアップするために(ユーザーIDにdictマッピング場所を構築する)手動で索引を作成することができます。これが遅すぎたり扱いにくい場合は、おそらくsqliteに切り替えるでしょう。これはPython(2.5)標準ライブラリに含まれています。

+0

ありがとうございました、私は以前に組み込みセットを使ったことはありません。これは、コード内で何が起こっているのかを少なくとも明白にするはずです。 – akoumjian

2

それは本当に少量のデータなら、私は、インデックスを気にし、おそらくちょうどヘルパー関数書き込みませ思います:

users = [ 
    dict(Name="Mr. Foo", Location="Boston", Type="Secondary"), 
    dict(Name="Mr. Bar", Location="New York", Type="Primary"), 
    dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"), 
    ] 

def search(dictlist, **kwargs): 
    def match(d): 
     for k,v in kwargs.iteritems(): 
     try: 
      if d[k] != v: 
       return False 
     except KeyError: 
      return False 
     return True 

    return [d for d in dictlist if match(d)] 

できるようになります。このような見栄えのクエリ:

result = search(users, Type="Secondary") 
+0

これはまた非常に役に立ちます。このコードの美しさは、人々がPythonで期待するものをより多く保持します。しかし、私は組合/交差点で提供するような柔軟性が少し好きです。 – akoumjian

5

私はsqliteが "過剰な"ものになるとは思わない - 標準のPython 2.5以降では、インストールする必要がなく、メモリやローカルディスクファイルのデータベースを作成して扱うことができる。本当に、どうすれば簡単にできますか?あなたは初期値を含むメモリ内のすべてのものをしたい、そしてそれらの初期値を表現するためにdictsを使用したい場合は、例えば...:

import sqlite3 

db = sqlite3.connect(':memory:') 
db.execute('Create table Users (Name, Location, Type)') 
db.executemany('Insert into Users values(:Name, :Location, :Type)', [ 
    dict(Name="Mr. Foo", Location="Boston", Type="Secondary"), 
    dict(Name="Mr. Bar", Location="New York", Type="Primary"), 
    dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"), 
    ]) 
db.commit() 
db.row_factory = sqlite3.Row 

、今お使いのメモリ内の小さな「DB」は行く準備ができて。ディスクファイルにDBを作成したり、テキストファイル、CSVなどから初期値を読み取るのは難しいことではありません。

問合せは...例えば、あなたが文字列の挿入と意志のパラメータ置換を混在させることができ、簡単かつ甘い、特に柔軟性がある:

def where(w, *a): 
    c = db.cursor() 
    c.execute('Select * From Users where %s' % w, *a) 
    return c.fetchall() 

print [r["Name"] for r in where('Type="Secondary"')] 

はちょうどよりエレガントが、同等のように、[u'Mr. Foo', u'Mr. Quux']発する

print [r["Name"] for r in where('Type=?', ["Secondary"])] 

と、ご希望のクエリがちょうどです:

print [r["Name"] for r in where('Location="Boston" or Type="Primary"')] 

などSエイリアス - 好きではないことは何ですか?

+0

利点は照会の柔軟性と、データベースをメモリからファイルへ簡単に移動したり、ファイルからエクスポートしたり、エクスポートするなどの選択肢があるようです。 欠点は、私が見ているように、追加のモジュール(巨額ではない)であり、誰かがコードを読んでいると、それらのオブジェクトメソッドが何であるかを知る必要があります。 これは素晴らしい解決策ですが、実際には最も簡単な解決策です。 – akoumjian

+1

もっとたくさんの人がすでにPython DB APIについてset、genexps、 '.union'などよりも知っていると思っていますか? - ) –

+1

私はちょうど1つの辞書、1つのセット、データベースオブジェクト、カーソルオブジェクト、および6つのメソッドがあります。 – akoumjian