Django/Python-그룹에 의해 개체는 일반적인 설정에서 다계
문제
이것은 부분은 알고리즘-논문(그것을 어떻게),부분 구현 질문(그것을 어떻게 최고!).나는 작업을 장고,그래서 저는 생각을 공유합니다.
파이썬에서,그것은 언급 할 가치가있는 이 문제는 약간과 관련된 는 방법-do-i-사용-파-itertoolsgroupby.
당신은 주어진 두 가지 장고의 모델 파생된 클래스:
from django.db import models
class Car(models.Model):
mods = models.ManyToManyField(Representative)
고
from django.db import models
class Mods(models.Model):
...
어떻게 하나의 목록을 얻을 차룹으로 자동차와 일반적인 설정의 개조 사용할 수 있습니까?
I.e.내가 원하는 클래스 likeso:
Cars_by_common_mods = [
{ mods: { 'a' }, cars: { 'W1', 'W2' } },
{ mods: { 'a', 'b' }, cars: { 'X1', 'X2', 'X3' }, },
{ mods: { 'b' }, cars: { 'Y1', 'Y2' } },
{ mods: { 'a', 'b', 'c' }, cars: { 'Z1' } },
]
나는 생각하고 다음과 같습니다.
def cars_by_common_mods():
cars = Cars.objects.all()
mod_list = []
for car in cars:
mod_list.append( { 'car': car, 'mods': list(car.mods.all()) }
ret = []
for key, mods_group in groupby(list(mods), lambda x: set(x.mods)):
ret.append(mods_group)
return ret
그러나,작동하지 않기 때문에(아마도 다른 이유 중)groupby 하지 않는 것 같은 그룹에 의해 개조합니다.나는 생각 mod_list 정리되어야 할 작업 groupby.모든 말을 저는 확신이 무언가가 간단하고 우아한 거기는 것이 모두 깨달음이 빛나.
환호 및 감사합니다!
해결책
목록을 먼저 정렬해 보셨습니까? 많은 데이터베이스 히트가 있지만 제안한 알고리즘은 작동해야합니다.
import itertools
cars = [
{'car': 'X2', 'mods': [1,2]},
{'car': 'Y2', 'mods': [2]},
{'car': 'W2', 'mods': [1]},
{'car': 'X1', 'mods': [1,2]},
{'car': 'W1', 'mods': [1]},
{'car': 'Y1', 'mods': [2]},
{'car': 'Z1', 'mods': [1,2,3]},
{'car': 'X3', 'mods': [1,2]},
]
cars.sort(key=lambda car: car['mods'])
cars_by_common_mods = {}
for k, g in itertools.groupby(cars, lambda car: car['mods']):
cars_by_common_mods[frozenset(k)] = [car['car'] for car in g]
print cars_by_common_mods
이제 그 질문에 대해 :
import collections
import itertools
from operator import itemgetter
from django.db import connection
cursor = connection.cursor()
cursor.execute('SELECT car_id, mod_id FROM someapp_car_mod ORDER BY 1, 2')
cars = collections.defaultdict(list)
for row in cursor.fetchall():
cars[row[0]].append(row[1])
# Here's one I prepared earlier, which emulates the sample data we've been working
# with so far, but using the car id instead of the previous string.
cars = {
1: [1,2],
2: [2],
3: [1],
4: [1,2],
5: [1],
6: [2],
7: [1,2,3],
8: [1,2],
}
sorted_cars = sorted(cars.iteritems(), key=itemgetter(1))
cars_by_common_mods = []
for k, g in itertools.groupby(sorted_cars, key=itemgetter(1)):
cars_by_common_mods.append({'mods': k, 'cars': map(itemgetter(0), g)})
print cars_by_common_mods
# Which, for the sample data gives me (reformatted by hand for clarity)
[{'cars': [3, 5], 'mods': [1]},
{'cars': [1, 4, 8], 'mods': [1, 2]},
{'cars': [7], 'mods': [1, 2, 3]},
{'cars': [2, 6], 'mods': [2]}]
이제 자동차 ID 및 모드 ID 목록을 얻었으므로 작업 할 완전한 개체가 필요한 경우 각 모델에 대한 전체 목록을 얻고 조회를 만들 수 있도록 각각에 대해 단일 쿼리를 할 수 있습니다. dict
그것들을 위해, 그들의 ID에 의해 키를 뿌린다. 그러면 나는 밥이 당신의 속담의 아버지의 형제라고 믿는다.
다른 팁
확인하다 다시 그룹. 템플릿에만 해당되지만 이런 종류의 분류는 어쨌든 프레젠테이션 계층에 속한 것 같습니다.
여기에는 몇 가지 문제가 있습니다.
GroupBy에 전화하기 전에 목록을 정렬하지 않았으며 이것이 필요합니다. 에서 itertools 문서:
일반적으로 반복적 인 것은 이미 동일한 키 기능에 정렬되어야합니다.
그런 다음 GroupBy가 반환 한 목록을 복제하지 않습니다. 다시, 문서화는 다음과 같습니다.
반환 된 그룹 자체는 그 자체가 groupby ()와 기본 반복을 공유하는 반복자입니다. 소스가 공유되기 때문에 GroupBY 객체가 발전되면 이전 그룹이 더 이상 보이지 않습니다. 따라서 해당 데이터가 나중에 필요한 경우 목록으로 저장해야합니다.
groups = [] uniquekeys = [] for k, g in groupby(data, keyfunc): groups.append(list(g)) # Store group iterator as a list uniquekeys.append(k)
그리고 마지막 실수는 세트를 키로 사용하는 것입니다. 그들은 여기서 일하지 않습니다. 빠른 수정은 정렬 된 튜플로 캐스팅하는 것입니다 (더 나은 솔루션이있을 수 있지만 지금은 생각할 수는 없습니다).
따라서 예에서 마지막 부분은 다음과 같아야합니다.
sortMethod = lambda x: tuple(sorted(set(x.mods)))
sortedMods = sorted(list(mods), key=sortMethod)
for key, mods_group in groupby(sortedMods, sortMethod):
ret.append(list(mods_group))
성능이 우려되는 경우 (예 : 페이지의 많은 자동차 또는 교통량이 많은 사이트), 비정규 화 합리적이며 부작용으로 문제를 단순화합니다.
다수의 관계를 제거하는 것은 약간 까다로울 수 있습니다. 나는 아직 그러한 코드 예제를 다루지 않았습니다.
당신은 도움이 대답.나는 멀리에서 이 문제를 해결합니다.'최적의 솔루션은 여전히 회피하지만,나는 어떤 생각입니다.
나도 언급해야한다는 통계 데이터의 설정과 작업에 어떤 영향을 주었을까요.75%에서의 사례 중 하나가 될 것입니다.에서 24%의 경우,두.에서 1%의 경우가,또는 세 이상입니다.에 대한 모든 모드가 있는 적어도 하나의 독특한 차지만,모드에 적용할 수 있는 수많은 자동차입니다.
제로 간주했다(하지만 구현되지 않)같은 것-그래서:
class ModSet(models.Model):
mods = models.ManyToManyField(Mod)
변 자동차
class Car(models.Model):
modset = models.ForeignKey(ModSet)
그것의 사소한 그룹입니다.modset:내가 사용할 수있는,재편성에 의해 제안으로 하비에르,예를 들어.그것은 보인다 간단하고 합리적인 우아한 해결책;생각은 많이 주시면 감사하겠습니다.