Форум сайта python.su
Доброго дня.
Сделал тут упражнение, всё работает, но, если у кого будет время посмотреть (оно простое), буду признателен за замечания.
#!/usr/local/bin/python
# -*- coding: utf-8 -*-
"""
Программа получает из файла sample.txt информацию о матчах и победах
игроков и возвращает таблицу результатов игр, сотрированную по возрастанию относительно побед каждого игрока, при равном количестве побед фамилии игроков сортируются по алфавиту.
Текстовый файл с информацией о матчах и победах выглядит так:
Beth Ana Charlie Dave
Ana vs Dave | 3:0
Charlie vs Beth | 3:1
Ana vs Beth | 2:3
Dave vs Charlie | 3:0
Ana vs Charlie | 3:1
Beth vs Dave | 0:3
Первая строка данного файла содержит имена игроков, далее запись в следующем формате:
<Имя> vs <Имя> | <Счёт>
Результатом действия программы является вывод на терминал такого сообщения:
Dave has won 2 matches and 6 sets
Ana has won 2 matches and 8 sets
Beth has won 1 matches and 4 sets
Charlie has won 1 matches and 4 sets
"""
def add_dic(dic, key, value):
""" ПП увеличивает значение ключа key в словаре dic на значение value, если ключ отсутсвоует - создаёт новуя пару key, value """
if dic.has_key(key):
dic[key] += int(value)
else:
dic[key] = int(value)
def sub_split(line, key):
""" ПП разбивает строку line на две подстроки по содержимому параметра key, удаляя начальные и концевые пробелы у результирующих подстрок """
r_1, r_2 = line.split(key)
r_1 = r_1.strip()
r_2 = r_2.strip()
return r_1, r_2
def invd(d):
""" ПП создаёт из ключей словаря d сортированный (по возрастанию значений и алфавиту ключей) список """
# Создаётся новый словарь
nd = {}
# Создаётся результирующий список
r = []
# Инвертируется заданный словарь
for i,j in d.iteritems():
nd.setdefault(j,[]).append(i)
# сортируется словарь
nd[j].sort()
print "nd = %s" % nd
# формируется плоский список путём конкатенации значений словаря nd
for i in nd:
r = r + nd[i]
# применяется reverse() к списку
r.reverse()
print "r = %s" % r
return r
# Begin programm
# sets - игры;
# matches - победы.
sets, matches = ({}, {})
# открывается файл с исходными данными
file = open("sample.txt")
# считывается первая строка из файла с исходными данными, содержащая имена игроков
names = file.readline().strip().split(' ')
# проход по файлу
for lines in file:
# пары записываются в paring, результат игр - в result
paring, result = lines.strip().split('|')
# p1, p2 будут содержать имена игроков в паре
p1, p2 = sub_split(paring, 'vs')
# r1, r2 будут содержать результат каждого из игроков пары
r1, r2 = sub_split(result, ':')
# запись результата матча в словарь sets для первого игрока пары
add_dic(sets,p1,r1)
# запись результата матча в словарь sets для второго игрока пары
add_dic(sets,p2,r2)
# в зависимости от результата игры добавляется имя победителя в словарь matches
if r1 > r2:
add_dic(matches,p1,1)
else:
add_dic(matches,p2,1)
# получение списка игроков, упорядоченного в соответствии от количества побед и в соответсвии с алфавитом
listwin = invd(matches)
# проход по упорядоченному списку игрогов с печатью результатов
for i in listwin:
print "%s has won %d matches and %d sets" % (i, matches[i], sets[i])
# закрытие файла с результатами игр
file.close()
Офлайн
я бы сделал чтение через регулярки.
import re
games = re.compile(r'([a-zA-Z]+) +vs +([a-zA-Z]+).+(\d)+:(\d)+')
Отредактировано (Июнь 8, 2011 11:48:32)
Офлайн
Регулярки - гуд, спасибо за регулятку, хотя я пытался средствами языка реализовать код на Perl6:
use v6;
my $file = open 'scores';
my @names = $file.get.split(' ');
my %matches;
my %sets;
for $file.lines -> $line {
my ($pairing, $result) = $line.split(' | ');
my ($p1, $p2) = $pairing.split(' vs ');
my ($r1, $r2) = $result.split(':');
%sets{$p1} += $r1;
%sets{$p2} += $r2;
if $r1 > $r2 {
%matches{$p1}++;
} else {
%matches{$p2}++;
}
}
my @sorted = @names.sort({ %sets{$_} }).sort({ %matches{$_} }).reverse;
for @sorted -> $n {
say "$n has won %matches{$n} matches and %sets{$n} sets";
}
Отредактировано (Июнь 8, 2011 13:06:13)
Офлайн
Навскидку:
- убейте add_dict. Это делается с помощью setdefault.
- убейте sub_split. Делайте как в перле.
- подумайте над изменением структуры данных, чтобы упростить сортировку и вывод
- по-моему у вас неправильно обрабатывается ничья
- имя переменной file скрывает builtin file - нехорошо
- переизбыток комментариев
- невнятные имена функций и переменных
- сделайте путь к файлу параметром скрипта
- запустите pylint и добейтесь оценки хотя бы 8
Если все это сделаете - кидайте код сюда, продолжим.
Отредактировано (Июнь 8, 2011 19:43:11)
Офлайн
Используйте Pylint для проверки своего кода, он многое расскажет ;)
Из замечаний Pylint:
- имеются строки длинной более 80 символов;
- не соблюдены конвенции именования переменных;
- вместо add_dict можно использовать defaultdict из модуля collections;
- r_1 = r_1.strip()
r_2 = r_2.strip()
return r_1, r_2
можно укоротить: return r_1.strip(), r_2.strip()
Офлайн
Доброго нового дня).
Оставил на месте подпрограммы (по причине склонности к подпрограммам)), остальные замечания постарался учесть, оставив на месте данные (условие такое), и без передачи имени файла в скрипт - хотел реализовать задание средствами языка, без подключения сторонних модулей. Ничьей, я думаю, в теннисе не бывает).
Получилось вот что:
#!/usr/local/bin/python
# -*- coding: utf-8 -*-
"""
Программа получает из файла sample.txt информацию о матчах и победах
игроков и возвращает таблицу результатов игр, сотрированную по возрастанию
относительно побед каждого игрока, при равном количестве побед фамилии
игроков сортируются по алфавиту.
Текстовый файл с информацией о матчах и победах выглядит так:
Beth Ana Charlie Dave
Ana vs Dave | 3:0
Charlie vs Beth | 3:1
Ana vs Beth | 2:3
Dave vs Charlie | 3:0
Ana vs Charlie | 3:1
Beth vs Dave | 0:3
Первая строка данного файла содержит имена игроков, далее запись в следующем
формате:
<Имя> vs <Имя> | <Счёт>
Результатом действия программы является вывод на терминал такого сообщения:
Dave has won 2 matches and 6 sets
Ana has won 2 matches and 8 sets
Beth has won 1 matches and 4 sets
Charlie has won 1 matches and 4 sets
"""
def add_dic(dic, key, value):
""" ПП увеличивает значение ключа key в словаре dic на значение value,
если ключ отсутсвует - создаёт новуя пару key, value """
dic[key] = dic.get(key, 0) + int(value)
def invd(somedict):
""" ПП создаёт из ключей словаря somedict сортированный
(по возрастанию значений и алфавиту ключей) список """
newdict = {}
resultdict = []
# Инвертируется заданный словарь
for i, j in somedict.iteritems():
newdict.setdefault(j,[]).append(i)
newdict[j].sort()
# формируется плоский список путём конкатенации значений словаря nd
for i in newdict:
resultdict = resultdict + newdict[i]
resultdict.reverse()
return resultdict
# SETS - сеты;
# MATCHES - победы.
SETS, MATCHES = ({}, {})
# открывается файл с исходными данными
FILERESULTS = open("sample.txt")
# считывается первая строка из файла с исходными данными,
# содержащая имена игроков
NAMES = FILERESULTS.readline().strip().split(' ')
for lines in FILERESULTS:
# paring - пары
# result - результат игры в виде "3:2"
paring, result = lines.strip().split(' | ')
player_1, player_2 = paring.split(' vs ')
result_player_1, result_player_2 = result.split(':')
add_dic(SETS, player_1, result_player_1)
add_dic(SETS, player_2, result_player_2)
# в зависимости от результата игры добавляется имя победителя в словарь
# MATCHES, и количество его побед увеличивается на 1
if result_player_1 > result_player_2:
add_dic(MATCHES, player_1, 1)
else:
add_dic(MATCHES, player_2, 1)
# получение списка игроков, упорядоченного в соответствии от количества побед
# и в соответсвии с алфавитом
LISTWIN = invd(MATCHES)
for i in LISTWIN:
print "%s has won %d matches and %d sets" % (i, MATCHES[i], SETS[i])
FILERESULTS.close()
Отредактировано (Июнь 21, 2011 11:05:20)
Офлайн
Основную программу положите в функцию main, тогда не нужно будет извращаться с именами переменных. Вот так:http://www.artima.com/weblogs/viewpost.jsp?thread=4829
Насчет данных либо я вас не понял, либо вы меня. Я имел в виду что ваши set и matches приводят вас к необходимости иметь invd. Речь шла о неоптимальной внутренней структуре данных.
Посмотрите на реализацию PooH. Это приблизительно то, что я имел в виду.
Нежелание использовать стандартную библиотеку выглядит странно. Если у вас нормальный Питон, то стандартная библиотека там по любому есть. Вы, вероятно, путаете ее с внешними библиотеками. Нежелание использовать их в некоторых случаях оправдано.
Офлайн
Я, если честно, переписал пример с Перла для того, чтобы знакомому показать сходство тендеций, а в перловом примере нет подключаемых библиотек - там дефолтом содержимое комадной строки попадает в @ARGV.
Конечно, я могу вставить import sys, да решил идеологически выдержать). Ок, я прочту artima.com, спасибо.
Офлайн
EdПрошу прощения, я вчера случайно свой пост потер. вот код
Посмотрите на реализацию PooH. Это приблизительно то, что я имел в виду.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
def parse(s):
names, sets = s.strip().split("|")
names = names.split("vs")
sets = sets.split(":")
return (names[0].strip(), int(sets[0])), (names[1].strip(), int(sets[1]))
draw = {}
def save_player_result(name, winner, sets):
rec = draw.setdefault(name, [0,0])
if winner:
rec[0] += 1
rec[1] += sets
with open(sys.argv[1]) as infile:
infile.next() # Первая строчка нафиг не нужна
for s in infile:
x, y = parse(s)
save_player_result(x[0], x[1]>y[1], x[1])
save_player_result(y[0], x[1]<y[1], y[1])
for name, result in sorted(draw.items(), key=lambda x: (x[1][0], x[0]), reverse=True):
print "%s has won %d matches and %d sets" % (name, result[0], result[1])
Офлайн