2009-09-24 1 views
13

의 나는 다음과 같은 서로 다른 특성을 가진 두 개 이상의 두 다스 객체가없는 가정 해 봅시다 :파이썬에서 작은 테이블?

UID, 이름, 값, 색상

나는 할 수 있도록하려면, 유형, 위치 Location = "Boston"또는 Type = "Primary"인 모든 객체를 호출하십시오. 클래식 데이터베이스 쿼리 유형 물건.

대부분의 테이블 솔루션 (pytables, * sql)은 이러한 작은 데이터 집합에 대해 과도한 부담입니다. 모든 객체를 반복하고 각 데이터 열에 대해 별도의 사전을 만들어야합니까 (새 객체를 추가 할 때 사전에 값 추가)?

이 이런 dicts 만들 것이다 :

가 { '보스톤 : 234, 654, 234]가'시카고 : 324, 765, 342]} - 이들 3 개 자리 항목 같은 것을 나타내며이 UID의 것을 .

알다시피이 질문은 약간의 고통이 될 것입니다.

대안에 대한 의견이 있으십니까?

답변

14

작은 관계형 문제의 경우 Python에 내장 된 sets을 사용하는 것을 좋아합니다. 위치 = '보스턴'OR 유형의 예를 들어

= '기본',이 데이터가 있다면 :

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 ... 쿼리를 수행 할 수 있습니다

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) 

또는 단 하나의 표현으로 :

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

의 기능을 사용할 수도 있습니다. 10을 사용하여 상당히 효율적인 데이터 쿼리를 생성합니다.

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

또한 일의 속도를 (사용자 ID에 dict 매핑 위치를 구축) 수동으로 인덱스를 만들 수있다 : 예를 들어 당신은 GROUP BY city 비슷한 작업을 수행하려는 경우. 이것이 너무 느리거나 다루기 힘들면 아마도 파이썬 (2.5) 표준 라이브러리에 포함되어있는 sqlite으로 전환 할 것입니다.

+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

이것은 또한 매우 유용합니다. 이 코드의 미학은 사람들이 파이썬에 기대하는 바를 유지합니다. 그러나 나는 약간의 융통성이있어 노동 조합/교차점을 제공하는 것처럼 보인다. – akoumjian

5

내가 sqlite가가 "과잉"이 될 것이라고 생각하지 않는다 - 그것은 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 eriously - 무엇을 좋아하지 않아?

+0

이점은 질의에서 훨씬 더 융통성이 있으며 데이터베이스를 메모리에서 파일로 쉽게 이동하고 파일을 내보내는 옵션이 있습니다. 단점은 내가 본 것처럼, 추가 모듈 (엄청난 거래는 아님), 코드를 읽는 다른 누군가가 모든 객체 메소드가 무엇인지 알아야합니다. 괜찮은 해결책이지만, 가장 간단한 imho는 아닙니다. – akoumjian

+1

더 많은 사람들이 이미 세트, genexps,'.union' 등보다 파이썬 DB API에 대해 알고 싶습니다. –

+1

하나의 사전, 하나의 세트 및 루프를 사용할 때보 다 훨씬 더 우아함을 볼 수 있습니다 데이터베이스 개체, 커서 개체 및 여섯 가지 방법이 있습니다. – akoumjian