-1

これは私の最初の投稿です。生徒数を尋ねる関数があります。次に、各学生について、最初の 3 行に次の情報が含まれます。学生 ID、名前、およびその学期に受講したコースの数。これで、コースごとに、コース番号、単位時間、および学生が獲得したスコアのパーセンテージが一覧表示されます。

def rawdata():
    semester = 1
    if semester == 1:
        raw_file = open('raw_data.txt', 'a')
        total = 0.0
        total2 = 0.0
        num_students = int(input('Enter number of students: '))        
        for student in range(num_students):
            raw_file.write('Start' + '\n')
            student_id = input('Enter student ID: ')
            name = input('Enter Name: ')
            num_classes = int(input('Enter number of courses taken: '))
            raw_file.write(student_id + '\n')
            raw_file.write(name + '\n')
            raw_file.write(str(num_classes) + '\n')
            for classes in range(num_classes):
                course_number = input('Enter Course Number: ')
                credits = int(input('Enter Credit Hours: '))
                GPA1 = float(input('Enter percentage grade for class: '))
                raw_file.write(course_number + '\n')
                raw_file.write(str(credits) + '\n')
                raw_file.write(str(GPA1) + '\n')
                total += credits
            raw_file.write('End' + '\n')
        raw_file.close()
        print('Data has been written')

すべてのデータは txt ファイルにリストされているので、次のように raw_data.txt からこの情報を取得する必要があります (入力によって異なります)。

Start
eh2727
Josh D
2
MAT3000
4
95.0
COM3000
4
90.0
End
Start
ah2718
Mary J
1
ENG3010
4
100.0
End

それを処理して、各学生の GPA を計算できるようにします。開始/終了に含まれる各学生の情報ブロックがありますが、GPA を計算するために処理関数でこの情報を読み取る方法がわかりません。これは私がこれまでに持っているものです:

def process():
    data = open('raw_data.txt', 'r')
    results = open('process_results.txt', 'w')
    buffer = []
    for line in data:
        if line.startswith('Start'):
            buffer = []
        buffer.append(line)
        if line.startswith("End"):
            for outline in buffer:
                results.write(outline)

これは単に結果テキストにすべてを書き込むだけで、各ブロックの情報を個別に処理して GPA を計算する方法がわかりません。どんな助けでも大歓迎です。

4

3 に答える 3

1

学生の記録を処理するためのステート マシンを開発する必要があります。'if line.strip() == 'Start' で正しい軌道に乗っています。これはレコードの始まりを示す歩哨です。この時点でできることは、processStudentRecord = true というフラグを設定することです。これにより、次の 'for line in data' でのパススルーで、取得した行がレコードの一部であることがわかります。フラグを設定した後は、その if ループを壊して、たくさんの elif を用意する必要がないようにする必要があります。

processStudentRecord = False
for line in data:
  if line.strip() == 'Start':
    processStudentRecord = True
    expecting            = "student_id"
    # break here so you go immediately to the next line
  if line.strip() == 'End':
    processStudentRecord = False
    # break here so you go immediately to the next line
  if processStudentRecord:
    # keep track of where you are in the student record
    if expecting == "student_id":
      # extract the student name and then proceed to the next expected line
      expecting = "student_name"
    elif expecting == ""

などなど。これは、これを行う「手続き型」の方法であることに注意してください。オブジェクト指向または機能的なソリューションを発明できます。

于 2012-07-05T21:09:11.940 に答える
1

データを .txt ファイルに書き出すのは独自のコードであるため、JSON や XML など、機械読み取り用のより簡単でフォールト トレラントな形式で書き込むことを検討してください。または、pickle または cpickle を使用してデータをシリアル化し、再度読み込むことを検討することもできます。

とにかく、あなたの質問に進みましょう:ファイルの読み方。残念ながら、解析されたデータで何をしたいのかを教えてくれません。ここで印刷したいと思います。通常、もちろん、学生とコースを説明する素敵なクラスを作成します。

あなたのようなファイルの解析には、文字列メソッド split() をよく使用します。split() はあなたの親友です。文字列メソッドの詳細については、python ドキュメントを参照してください。

f = open('raw_data.txt', 'rt')
data = f.read()

students = data.split('Start\n')[1:]

for s in students:
    lines = s.split('\n')
    id = lines[0]
    name = lines[1]

    nrcourses = int(lines[2])

    line = 2
    courses = []
    for n in range(nrcourses):
        number = lines[line+1]
        credit = lines[line+2]
        score = lines[line+3]
        courses.append((number, credit, score))
        line += 3

    print 'id: %s; name %s; course list %s' % (id, name, courses)

f.close()
于 2012-07-05T21:09:50.070 に答える
0

これはかなりのコードですが、それがどのように機能するかを理解するまでそれをたどると、多くのことを学ぶことができます。

まず、クラスマークを取得してポイントに変換する必要があります。これを13のカスケードとして書くこともできますがif、私はデータ駆動型のアプローチが好きです。

import bisect

def grade_points(pct):
    grade  = [  0,  50,  53,  57,  60,  63,  67,  70,  73,  77,  80,  85,  90]
    points = [0.0, 0.7, 1.0, 1.3, 1.7, 2.0, 2.3, 2.7, 3.0, 3.3, 3.7, 4.0, 4.0]
    if 0 <= pct <= 100:
        # find the highest grade <= pct
        idx = bisect.bisect_right(grade, pct) - 1
        # return the corresponding grade-point
        return points[idx]
    else:
        raise ValueError('pct value should be in 0..100, not {}'.format(pct))

次に、Studentクラスで、学生ごとのデータを簡単に追跡できるようにします。

class Student(object):
    str_format = '{id:>8}  {name}  {gpa}'

    def __init__(self, *args):
        if len(args)==1:    # copy constructor
            student = args[0]
            self.id, self.name, self.classes = student.id, student.name, student.classes
        elif len(args)==3:  # "id", "name", [classes,]
            self.id, self.name, self.classes = args
        else:
            raise ValueError('Failed call to {}.__init__{}'.format(type(self), args))

    @property
    def gpa(self):
        points = sum(hour*grade_points(grade) for code,hour,grade in self.classes)
        hours  = sum(hour                     for code,hour,grade in self.classes)
        return points / hours

    def __str__(self):
        return type(self).str_format.format(id=self.id, name=self.name, classes=self.classes, gpa=self.gpa)

    def __repr__(self):
        return "{}('{}', '{}', {})".format(type(self).__name__, self.id, self.name, self.classes)

したがって、学生を作成して、次のように彼女のGPAを見つけることができます。

sally = Student('ab2773', 'S Atkins', [
    ('MAT3000', 4, 81.0),
    ('ENG3010', 4, 85.0)
])
print sally     # '  ab2773  S Atkins  3.85'

次に、学生をファイルとの間でストリーミングできるようにする必要があります。これは、OOPの観点からは少し面倒です。これは、StudentオブジェクトがFileオブジェクトについて何も知る必要がないため、またはその逆であるためです。さらに、より良いファイル形式(Student)にアップグレードしたいためです。オブジェクトは、互換性のない複数のファイルタイプについて知る必要はありません。

Studentをサブクラス化することでこれにアプローチしました。私はStudent.__init__メソッドを前後にキャストでき、サブクラス用に書き直す必要がないように記述したので、サブクラスは自分自身を厄介なファイル形式との間で変換する方法を知っています。

class NastyFileStudent(Student):
    @classmethod
    def from_strings(cls, strings):
        if len(strings) > 3 and len(strings) == 3 + int(strings[2])*3:
            codes  = strings[3::3]
            hours  = map(int,   strings[4::3])
            grades = map(float, strings[5::3])
            return Student(strings[0], strings[1], zip(codes, hours, grades))
        else:
            # not enough data returned - probably end of file
            return None

    def __str__(self):
        data = [self.id, self.name, str(len(self.classes))] + [str(i) for c in self.classes for i in c]
        return '\n'.join(data)

ファイルにはStudentデータがあることはわかっていますが、内容については何もわかりません。

class NastyFile(object):
    START = 'Start'
    END   = 'End'

    @staticmethod
    def _read_until(endfn, seq):
        is_end = endfn if callable(endfn) else lambda s: s==endfn
        data = []
        for s in seq:
            if is_end(s):
                break
            else:
                data.append(s)
        return data

    def __init__(self, name, mode='r'):
        self.name = name
        self.mode = mode
        self._f = open(name, mode)
        self.lines = (ln.strip() for ln in self._f)

    def __del__(self):
        self._f.close()

    def __iter__(self):
        return self

    def next(self):
        _       = NastyFile._read_until(NastyFile.START, self.lines)
        strings = NastyFile._read_until(NastyFile.END,   self.lines)

        student = NastyFileStudent.from_strings(strings)
        if student is None:
            raise StopIteration()
        else:
            return student

    def read(self):
        return list(self)

    def write(self, s):
        if not hasattr(s, '__iter__'):
            s = [s]
        for student in s:
            self._f.write('{}\n{}\n{}\n'.format(NastyFile.START, str(NastyFileStudent(student)), NastyFile.END))

これで、学生の記録のファイルを次のように読み書きできます。

>>> students = NastyFile('student_records.txt').read()

>>> for s in students:
...     print s
  eh2727  Josh D  4.0
  ah2718  Mary J  4.0

>>> students.append(sally)

>>> students.sort(key=lambda s: s.name.rsplit(None,1)[-1])  # sort by last name

>>> for s in students:
...     print s
  ab2773  S Atkins  3.85
  eh2727  Josh D  4.0
  ah2718  Mary J  4.0

>>> newfile = NastyFile('new_records.txt', 'w')
>>> newfile.write(students)

>>> for i,s in enumerate(NastyFile('new_records.txt'), 1):
...     print '{:>2}: {}'.format(i, s)
 1:   ab2773  S Atkins  3.85
 2:   eh2727  Josh D  4.0
 3:   ah2718  Mary J  4.0
于 2012-07-06T02:43:22.270 に答える