2

ジェネレーター/イテレーターを介してアクセスする大量のデータがあります。データセットの処理中に、そのデータセット内のいずれかのレコードに、処理中の現在のレコードの属性と同じ値を持つ属性があるかどうかを判断する必要があります。これを行う 1 つの方法は、ネストされた for ループを使用することです。たとえば、学生のデータベースを処理する場合、次のようなことができます。

def fillStudentList():
    # TODO: Add some code here to  filll
    # a student list
    pass

students = fillStudentList()
sameLastNames = list()
for student1 in students1:
  students2 = fillStudentList()
  for student2 in students2:
    if student1.lastName == student2.lastName:
        sameLastNames.append((student1, student2))

上記のコード スニペットはかなり改善される可能性があります。このスニペットの目的は、ネストされた for ループ パターンを示すことです。

ここで、クラス Student、イテレータであるクラス Students、およびメモリ効率の良い方法 (別のイテレータなど) でデータへのアクセスを提供するクラス Source があるとしましょう...

以下に、このコードがどのように見えるかをスケッチしました。この実装を改善する方法についてアイデアを持っている人はいますか? 目標は、フィルター処理されたセットを処理できるように、同じ属性を持つ非常に大きなデータセット内のレコードを検索できるようにすることです。

#!/usr/bin/python

from itertools import ifilter

class Student(object):
    """
    A class that represents the first name, last name, and
    grade of a student.
    """
    def __init__(self, firstName, lastName, grade='K'):
        """
        Initializes a Student object
        """
        self.firstName = firstName
        self.lastName = lastName
        self.grade = grade

class Students(object):
    """
    An iterator for a collection of students
    """
    def __init__(self, source):
        """
        """
        self._source = source
        self._source_iter = source.get_iter()
        self._reset = False

    def __iter__(self):
        return self

    def next(self):
        try:
            if self._reset:
                self._source_iter = self._source.get_iter()
                self._reset = False
            return self._source_iter.next()
        except StopIteration:
            self._reset = True
            raise StopIteration

    def select(self, attr, val):
        """
        Return all of the Students with a given
        attribute
        """
        #select_iter = self._source.get_iter()
        select_iter = self._source.filter(attr, val)
        for selection in select_iter:
            # if (getattr(selection, attr) == val):
            #    yield selection
            yield(selection)

class Source(object):
    """
    A source of data that can provide an iterator to 
    all of the data or provide an iterator to the
    data based on some attribute
    """
    def __init__(self, data):
        self._data = data

    def get_iter(self):
        """
        Return an iterator to the data
        """
        return iter(self._data)

    def filter(self, attr, val):
        """
        Return an iterator to the data filtered by some
        attribute
        """
        return ifilter(lambda rec: getattr(rec, attr) == val, self._data)

def test_it():
    """
    """
    studentList = [Student("James","Smith","6"),
                   Student("Jill","Jones","6"),
                   Student("Bill","Deep","5"),
                   Student("Bill","Sun","5")]
    source = Source(studentList)
    students = Students(source)
    for student in students:
        print student.firstName

        for same_names in students.select('firstName', student.firstName):
            if same_names.lastName == student.lastName:
                continue
            else:
                print " %s %s in grade %s has your same first name" % \
                (same_names.firstName, same_names.lastName, same_names.grade)

if __name__ == '__main__':
    test_it()
4

2 に答える 2

2

ネストされたループは O(n**2) です。代わりにソートを使用してitertools.groupby、O(nlogn) のパフォーマンスを向上させることができます。

students = fill_student_list()
same_last_names = [list(group) for lastname, group in 
                   groupby(sorted(students, key=operator.attrgetter('lastname'))]

一般に、データベースに支えられたORMが行うことをしようとしているようです。自分で行うのではなく、すでに存在する多くの ORM のいずれかを使用してください。良い Python ORM ソリューションは何ですか?を参照してください。リストのために。それらは、自分でコーディングするものよりも最適化され、強力になります。

于 2012-04-11T04:56:21.317 に答える
1

おそらく、このようなものがうまくいくでしょう(これはO(n)です)

from collections import defaultdict
students = fillStudentList()
sameLastNames = defaultdict(list)
for student in students:
    sameLastNames[student.lastName].append(student)

sameLastNames = {k:v for k,v in sameLastNames.iteritems() if len(v)>1}
于 2012-04-11T04:58:10.970 に答える