0

私は2つの異なるオブジェクトを持っています。それらの1つは、リストまたはタプル属性内の他のN個のタイプオブジェクトをラップします。教室の生徒を例にとってみましょう。

class Student:
    def __init__(self, name):
        self.name = name

class ClassRoom:
    def __init__(self, students):
        self.students = students

もちろん、StudentインスタンスとClassRoomインスタンスのヒープがあります。

john, sam = Student('John'), Student('Sam')
patrick, michael, bill = Student('Patrick'), Student('Michael'), Student('Bill')
klass1 = ClassRoom([john, sam])
klass2 = ClassRoom([patrick, michael, bill])

各生徒は名前が一意であり、参照によって生徒の教室にアクセスすることはできないことを考慮してください。

sam.get_classroom() # Student class doesn't support this :(

そして、私たちはその仕事をするヘルパー関数を持っています:

def get_classroom_by_student(klasses, student_name):
    for klass in klasses:
        for student in klass.students:
            if student.name==student_name:
                return klass
                # Or yield if a student belongs to more than one class

sams_class = get_classroom_by_student([klass1, klass2], 'Sam')
bills_class = get_classroom_by_student([klass1, klass2], 'Bill')

「フラットはネストよりも優れている」ので、効率的なジェネレーターを作成するにはどうすればよいですか、またはこのヘルパー関数を実装するためのPythonの方法はありますか?

4

3 に答える 3

1

データモデルを変更したくない場合は、次のように関数を書き直すことができます。

def get_classroom_by_student(klasses, student_name):
    for klass in klasses:
        for student in klass.students:
            if student.name==student_name:
                yield klass

これは、より同等ではありません

def get_classroom_by_student(klasses, student_name):
    combinations = []
    for klass in klasses:
        for student in klass.students:
            if student.name==student_name:
                combinations.append(klass)
    return combinations

ただし、クリーナーは次のとおりです。

def get_classroom_by_student(klasses, student):
    for klass in klasses:
        for s in klass.students:
            if s is student:
                yield klass

これは、ネストされたリスト内包表記を使用して書き直すことができます。

def get_classroom_by_student(klasses, student):
    return [klass for klass in klasses for s in klass.students if s is student]

またはさらに短い

def get_classroom_by_student(klasses, student):
    return [klass for klass in klasses if student in klass.students]
于 2012-09-28T19:40:49.760 に答える
0

これはどう:

class Student:
    def __init__(self, name):
        self.name = name

class ClassRoom:
    def __init__(self, students):
        self.students = students

john, sam = Student('John'), Student('Sam')
patrick, michael, bill = Student('Patrick'), Student('Michael'), Student('Bill')

klass1 = ClassRoom([john, sam])
klass2 = ClassRoom([patrick, michael, bill])


def where_is(student, klasses):
    return next((x for x in klasses if student in x.students), None)

assert klass1 is where_is(john, [klass1, klass2])
assert klass2 is where_is(patrick, [klass1, klass2])

nobody = Student('foo')
assert None is where_is(nobody, [klass1, klass2])

next降伏バージョンの場合は、ジェネレータを省略して返します。

def where_is(student, klasses):
    return (x for x in klasses if student in x.students)

for klass in where_is(john, [klass1, klass2]):
    print klass
于 2012-09-28T19:50:41.197 に答える
0

したがって、これにはそれほど多くのネストはありません。基本的に、各生徒を教室にマッピングする辞書mを作成します。私の意見では、それはそれほど読みやすく、きれいではありません。

辞書を一度作成してから、それを使用して生徒のクラスを検索することをお勧めします。Djangoでモデルをチェックすることを強くお勧めします。彼らはあなたが探していることをはるかにクリーンな方法で行います。Djangoの優れている点は、教室と生徒の外部キー関係を設定すると、生徒のオブジェクトにメソッドが自動的に追加され、教室を検索できるようになることです。だからそれはあなたのためにすべての仕事をします。

from itertools import chain

def flatten(items):
    return list(chain.from_iterable(items))

def get_classroom_by_student(klasses, student_name):
    m = flatten([dict.fromkeys(k.students, k).items() for k in klasses])
    m = dict([(s.name, c) for s,c in m])
    return m[student_name]
于 2012-09-28T19:55:03.060 に答える