ответ JacobM - это абсолютно верный путь. Тем не менее, есть несколько вещей, которые следует иметь в виду при реализации того, что он описал. Вот небольшое руководство по игре на дому, которое поможет вам разобраться в хитрости в решении этой проблемы.
Если этот код предназначен для производственного использования, пожалуйста, используйте один из наиболее эффективных / кратких ответов в списке. Этот ответ предназначен для новичков в программировании.
Идея
Идея проста.
- Оставьте две переменные:
largest
и second_largest
.
- Перейти по списку.
- Если элемент больше
largest
, присвойте ему largest
.
- Если элемент больше
second_largest
, но меньше largest
, присвойте ему значение second_largest
.
Начало работы
Давайте начнем.
def two_largest(inlist):
"""Return the two largest items in the sequence. The sequence must
contain at least two items."""
for item in inlist:
if item > largest:
largest = item
elif largest > item > second_largest:
second_largest = item
# Return the results as a tuple
return largest, second_largest
# If we run this script, it will should find the two largest items and
# print those
if __name__ == "__main__":
inlist = [3, 2, 1]
print two_largest(inlist)
Хорошо, теперь у нас есть ответ JacobM как функция Python. Что происходит, когда мы пытаемся запустить его?
Traceback (most recent call last):
File "twol.py", line 10, in <module>
print two_largest(inlist)
File "twol.py", line 3, in two_largest
if item > largest:
UnboundLocalError: local variable 'largest' referenced before assignment
Очевидно, нам нужно установить largest
, прежде чем мы начнем цикл. Это, вероятно, означает, что мы должны установить second_largest
тоже.
Инициализация переменных
Давайте установим largest
и second_largest
в 0.
def two_largest(inlist):
"""Return the two largest items in the sequence. The sequence must
contain at least two items."""
largest = 0 # NEW!
second_largest = 0 # NEW!
for item in inlist:
if item > largest:
largest = item
elif largest > item > second_largest:
second_largest = item
# Return the results as a tuple
return largest, second_largest
# If we run this script, it will should find the two largest items and
# print those
if __name__ == "__main__":
inlist = [3, 2, 1]
print two_largest(inlist)
Хорошо. Давайте запустим его.
(3, 2)
Отлично! Теперь давайте проверим с inlist
, являющимся [1, 2, 3]
inlist = [1, 2, 3] # CHANGED!
Давайте попробуем.
(3, 0)
... Ох, ох.
Исправление логики
Наибольшее значение (3) кажется правильным. Второе по величине значение совершенно неверно. Что происходит?
Давайте разберемся, что делает функция.
- Когда мы начинаем,
largest
равно 0, а second_largest
также равно 0.
- Первый элемент в списке, на который мы смотрим, равен 1, поэтому
largest
становится 1.
- Следующий элемент равен 2, поэтому
largest
становится 2.
А как же second_largest
?
Когда мы присваиваем новое значение largest
, наибольшее значение фактически становится вторым по величине. Нам нужно показать это в коде.
def two_largest(inlist):
"""Return the two largest items in the sequence. The sequence must
contain at least two items."""
largest = 0
second_largest = 0
for item in inlist:
if item > largest:
second_largest = largest # NEW!
largest = item
elif largest > item > second_largest:
second_largest = item
# Return the results as a tuple
return largest, second_largest
# If we run this script, it will should find the two largest items and
# print those
if __name__ == "__main__":
inlist = [1, 2, 3]
print two_largest(inlist)
Давайте запустим.
(3, 2)
Фантастическая.
Инициализация переменных, часть 2
Теперь попробуем со списком отрицательных чисел.
inlist = [-1, -2, -3] # CHANGED!
Давайте запустим.
(0, 0)
Это совсем не правильно. Откуда взялись эти нули?
Оказывается, что начальные значения для largest
и second_largest
были на самом деле больше, чем все элементы в списке. Первое, что вы можете рассмотреть, - это установить largest
и second_largest
на минимально возможные значения в Python. К сожалению, Python не имеет наименьшего возможного значения. Это означает, что, даже если вы установите оба значения -1 000 000 000 000 000 000, список значений может быть меньше этого значения.
Так что лучше всего сделать? Давайте попробуем установить largest
и second_largest
для первого и второго элементов в списке. Затем, чтобы избежать двойного счета любых элементов в списке, мы смотрим только на часть списка после второго элемента.
def two_largest(inlist):
"""Return the two largest items in the sequence. The sequence must
contain at least two items."""
largest = inlist[0] # CHANGED!
second_largest = inlist[1] # CHANGED!
# Only look at the part of inlist starting with item 2
for item in inlist[2:]: # CHANGED!
if item > largest:
second_largest = largest
largest = item
elif largest > item > second_largest:
second_largest = item
# Return the results as a tuple
return largest, second_largest
# If we run this script, it will should find the two largest items and
# print those
if __name__ == "__main__":
inlist = [-1, -2, -3]
print two_largest(inlist)
Давайте запустим.
(-1, -2)
Отлично! Давайте попробуем с другим списком отрицательных чисел.
inlist = [-3, -2, -1] # CHANGED!
Давайте запустим.
(-1, -3)
Подождите, что?
Инициализация переменных, часть 3
Давайте снова пройдемся по нашей логике.
largest
установлен на -3
second_largest
установлено на -2
Подождите прямо здесь. Уже это кажется неправильным. -2 больше чем -3. Это то, что вызвало проблему? Давайте продолжим.
largest
установлен в -1; second_largest
устанавливается на старое значение largest
, которое равно -3
Да, похоже, это проблема. Нам нужно убедиться, что largest
и second_largest
установлены правильно.
def two_largest(inlist):
"""Return the two largest items in the sequence. The sequence must
contain at least two items."""
if inlist[0] > inlist[1]: # NEW
largest = inlist[0]
second_largest = inlist[1]
else: # NEW
largest = inlist[1] # NEW
second_largest = inlist[0] # NEW
# Only look at the part of inlist starting with item 2
for item in inlist[2:]:
if item > largest:
second_largest = largest
largest = item
elif largest > item > second_largest:
second_largest = item
# Return the results as a tuple
return largest, second_largest
# If we run this script, it will should find the two largest items and
# print those
if __name__ == "__main__":
inlist = [-3, -2, -1]
print two_largest(inlist)
Давайте запустим.
(-1, -2)
Отлично.
Заключение
Итак, вот код, красиво прокомментированный и отформатированный. Там также были найдены все ошибки, которые я мог найти. Наслаждайтесь.
Однако, предполагая, что это действительно домашний вопрос, я надеюсь, что вы получите полезный опыт, увидев, как несовершенный фрагмент кода медленно улучшается. Я надеюсь, что некоторые из этих методов будут полезны в будущих заданиях по программированию.
Эффективность
Не очень эффективно. Но для большинства целей все должно быть в порядке: на моем компьютере (Core 2 Duo) список из 100 000 элементов может быть обработан за 0,27 секунды (с использованием timeit
, в среднем за 100 прогонов).