Введення даних з файлу і оптимальне використання list comprehension

Розберемо задачу 8358 з e-olymp. Джерело задачі —  2018 Azerbaijan School Competition, II Stage, April 8, Problem K. На e-olimp на дату написання статті задача опублікована лише російською, тому перекладаю сам:

 

Середнє значення – 1

(https://www.e-olymp.com/uk/problems/8358)

 

Проект "Середня вага школяра школи" вирішили виконати Мамед з Самедом. Що вони будуть робити з цим числом, вони не розкривають. Вони попросили зважитися всіх учнів школи і занесли результати в таблицю. Допоможіть їм підрахувати середню вагу учнів. Але вони просять, щоб учнів з найбільшою і з найменшим вагою не враховувати. Єдине їх упущення, вони не підрахували загальну кількість учнів, але це, звичайно, не завадить вам підрахувати то, що вони просять.

 

Вхідні дані

У кількох рядках задані ваги учнів в кілограмах, розділених пропусками (одним або кількома) або символом кінця рядка. Читати ваги учнів до кінця введення.

 

Вихідні дані

Середня вага учнів школи без урахування учнів з найбільшою і найменшою вагою. Відповідь виводити з точністю до кілограм.

 

Ліміт часу 1 секунда

Ліміт використання пам'яті 128 MB

 

Вхідні дані # 1

40 23 27

  59 68 23 84 27

53 46

 

Вихідні дані # 1

46

 


 

В першу чергу треба врахувати, що через невідому кількість рядків вхідних даних, єдиним способом отримати  вхідні дані – це використати введення з файлу. Будемо читати рядки з файлу до тих пір, поки не закінчиться файл. Пропоную кожний рядок вхідних даних записувати в тимчасовий список, а далі елементи цього тимчасового списку додавати до основного списку. Код цієї частини програми:

 

 

inputfile = open('input.txt', 'r')

outputfile = open('output.txt', 'w')

weights = []

for line in inputfile:

    lst = [int(x) for x in line.split()]

    weights.extend(lst)

 

Далі ми можемо використати list comprehension з умовою, наприклад, так ефектно:

 

weights = [x for x in weights if x != max(weights) and x != min(weights)]

 

В результаті в новому списку weights будуть лише потрібні дані, всі максимальні і мінімальні ваги в новий список  weights не попадуть. Але так робити не треба, тому що це неоптимально по часу і непрофесійно на співбесіді на роботу. Річ в тому, що при кожній ітерації циклу, проходить порівняння значення елементу списку з максимальним і мінімальним елементом списку. І кожного разу python  буде обраховувати максимальне і мінімальне значення. Так як список у нас протягом обробки циклом не змінюється, то буде правильним визничити максимальне і мінімальне значення списку до циклічного перебору:

 

max_weights =  max(weights)

min_weights =  min(weights)

weights = [x for x in weights if x != max_weights and x != min_weights]

 

Зверніть увагу на інформативність змінних. В олімпіадному програмуванні часто поспішають і так змінні не називають, а дарма. Рекомендую назви змінним давати розумно, у професійному програмуванню так і роблять.

 

Ну і на останок, в умові задачі є округлення, це в Python дуже дискутивна тема. Як мінімум, нагадаю, що  Python версії 2 виконує так зване «арифметичне округлення», як Pascal, C++ і як на уроках математики, а Python версії 3 при використанні функції round() виконує так зване «банківське округлення» або «округлення до парного». В даній задачі тести обрані таким чином, що при здачі в Python версії 3 ніяких проблем немає, про округлення в Python 3 на «Плетиві» буде окрема стаття, а тим, хто про дива округлення чує вперше, банківське округлення в Python 3 (і не лише там) виглядає так:

>>> round(1.5)

2

>>> round(2.5)

2

>>> round(3.5)

4

>>> round(4.5)

4

>>> round(5.5)

6

>>> round(6.5)

6

>>> round(7.5)

8

>>> round(8.5)

8

 

І не забувайте прибиратися після себе. Принцип простий. Ви відкрили якийсь файли? Ви відкрили, вам і закривати. 

Документація третього Python вимагає так:

If you’re not using the with keyword, then you should call f.close() to close the file and immediately free up any system resources used by it. If you don’t explicitly close a file, Python’s garbage collector will eventually destroy the object and close the open file for you, but the file may stay open for a while. Another risk is that different Python implementations will do this clean-up at different times.

Успіхів! 

 


 

Вхід для своїх