Есть ли способ ссылаться на два атрибута объекта в списке?

#python

#python

Вопрос:

Я хочу знать, кто самый высокий спортсмен (объект) в списке объектов. Если я хочу его распечатать, я попытался написать это:

 print ("The greater height is",max(x.height for x in athletes_list),"meters.")
  

Он показывает рост более высокого спортсмена, но я не знаю, как получить его имя таким образом, поместив все команды в тело print. Есть ли какой-либо способ сделать это?

Я знаю, что это возможно, создав для этого:

 for i in athletes_list:
    if i.height==max(x.height for x in athletes_list):
        print ("The taller athlete is",i.name,"with",i.height,"meters.")
  

Возможно ли получить обе информации только в теле print?
Извините за плохой английский.

Комментарии:

1. Что, если есть более одного спортсмена с самым высоким ростом?

2. Вы ищете argmax. В Python это делается следующим образом max(iterable, key=lambda x: ...)

3. Хорошая точка зрения, @thefourtheye. Я попытаюсь найти это решение самостоятельно, используя ответы, которые я нашел здесь, и немного логики. Но если кто-то хочет указать способ, это было бы неплохо 😉

Ответ №1:

Перечитайте свой вопрос. Ответ по-прежнему положительный. Используйте format метод строк:

 print("The taller athlete is {0.name} with {0.height} meters.".format(max(athletes_list, key=lambda a: a.height)))
  

Комментарии:

1. Да, он также может отсортировать список: athletes_list.sort(key=lambda a: a.height, reverse=True) и выбрать первого спортсмена.

2. @LaurentLAPORTE: Конечно, если ему нужен только первый, стоимость a sort равна O(n log n) , по сравнению с O(n) for max , так что это ценно, только если ему действительно нужно, чтобы они все были отсортированы.

3. @LaurentLAPORTE плюс, который изменяет список, что может иметь последствия позже

4. Да, согласен с вами, я только даю другое решение в комментарии (это не ответ).

5. Потрясающе! Большое спасибо!

Ответ №2:

Используйте max для обоих значений (сначала с высотой):

 from future_builtins import map  # Only on Py2, to get generator based map
from operator import attrgetter

# Ties on height will go to first name alphabetically
maxheight, name = max(map(attrgetter('height', 'name'), athletes))
print("The taller athlete is", name, "with", maxheight, "meters.")
  

Или таким образом, связи разрешаются по порядку появления, а не по имени:

 maxheight, name = attrgetter('height', 'name')(max(athletes, key=attrgetter('height')))
  

Комментарии:

1. Большинство разработчиков действительно не понимают attrgetter , я предпочитаю использовать lambda with max() , как в других ответах.

2.@LaurentLAPORTE: Большинство разработчиков также не используют map правильно (если вы используете его с lambda , вы пессимизируете и должны просто использовать listcomp или genexpr вместо этого). Я предпочитаю attrgetter и itemgetter , потому что они самодокументируются и сигнализируют «здесь нет трюков». Они также быстрее и хорошо масштабируются для одновременного получения многих значений. Я использую lambda s только тогда, когда есть хитрости (например, ключ сортировки lambda x: x[0], -x[2], x[1] , обратите внимание на - on x[2] , который делает itemgetter(0, 2, 1) непригодным), поэтому, когда я вижу lambda s в своем коде, я знаю, что нужно проверить более тщательно. Хотя не стоит опускать голос.

3. Хороший вариант. Работает как шарм, но я думаю, что этот способ немного сложнее, чем lamba с max() на данный момент.

4. @EduardoM: Верно. Вторая версия attrgetter бессмысленна; Я бы действительно просто сохранил спортсмена и использовал tallest.height и tallest.name , когда просматриваю каждый из них только один раз. Я просто развлекаюсь здесь. 🙂