Найти минимальное и максимальное значение нескольких элементов в Python

#python

#python

Вопрос:

Я новичок как на форуме, так и в Python, я надеюсь, что сделаю все правильно (скажите мне все, что я делаю неправильно, чтобы я мог это улучшить).

По поводу моего вопроса: у меня много объектов класса (это правильное имя?) В списке (весь этот объект класса представляет собой прямоугольник внутри матрицы (= вложенный список)).

Весь этот прямоугольник имеет множество атрибутов, некоторые из них: «X_SX«, «Y_SX«, «X_DX«, «Y_DX» (они являются координатами вершины слева вверх («X_SX», «Y_SX») и вершины справа вниз («X_DX», «Y_DX») прямоугольника.

Я должен найти минимальное значение X_SX и Y_SX и максимальное значение X_DX и Y_SX. Это то, что я сделал:

 def find_box(rectangles):
    x_sx = (min(getattr(rec, 'x_sx') for rec in rectangles))
    y_sx = (min(getattr(rec, 'y_sx') for rec in rectangles))
    x_dx = (max(getattr(rec, 'x_dx') for rec in rectangles))
    y_dx = (max(getattr(rec, 'y_dx') for rec in rectangles))
 

Это действительно работает, но мне было интересно, есть ли способ сделать это лучше и избежать вызова цикла for 4 раза в одном и том же списке

ПРИМЕЧАНИЕ: я не уверен, что я плохо это объясняю, но для лучшего понимания это список «прямоугольники», где «Прямоугольник» — это класс, который я определил:

 [<__main__.Rettangolo object at 0x000001FAF3971C70>, <__main__.Rettangolo object at 0x000001FAF36E2B80>, <__main__.Rettangolo object at 0x000001FAF3971850>, <__main__.Rettangolo object at 0x000001FAF3B55A30>]
 

Спасибо за ваше время и вашу помощь!

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

1. Вы повторили прямоугольники четыре раза. И лучше, чтобы, повторив один раз, получить значения x_sx, y_sx, x_dx, y_dx и сохранить их в отдельных списках. И в конце получите минимальное и максимальное значения для каждого списка.

2. @YuriRen получение минимального и максимального значений этих списков (внутри) требует повторного выполнения цикла, поэтому вы фактически выполняете цикл еще один раз. Хотя это может облегчить чтение.

Ответ №1:

Я согласен с Туруном Амбартаненом в том, что ваш код читается как есть. Если вы хотите ускорить процесс, я укажу вам на стандартную библиотеку numpy python (numpy — это «числовой python»).

Массивы Numpy позволят вам исключить итерации, если это желательно. Если в вашем списке много прямоугольников, вы получите большой прирост производительности, используя их. (Я думаю, что в вашем примере я вижу только четыре, так что это может выйти за рамки того, что вы ищете.) Недостатком массивов является то, что они могут привести к усложнению чтения кода. Возможно, я выхожу за рамки того, что пытается изучить новичок в python, но здесь идет:

 ## import numpy and give it the short name 'np'
import numpy as np

## Define a numpy array from the lists.
## np.array takes lists and turns them into the axes of
## an array.

corners = np.array([[rec.x_sx,
                     rec.x_sy, 
                     rec.x_dx, 
                     rec.x_dy] for rec in rectangles])

## Numpy provides functions for doing math along the rows
## and columns of an array. (And lots more!)
## np.max returns the largest element in an array
## the axis argument says which dimension to find the max
## on. This produces a 1 row, 4 column array

maxima = np.max(corners, axis = 0)

## And for the min-values
minima = np.min(corners, axis = 0)

##Edit: finally, so the values are stored as you did above:
x_sx = maxima[0]
y_sx = maxima[1]
x_dx = minima[2]
y_dx = minima[3]
 

Вы можете индексировать массивы numpy способами, аналогичными спискам (за исключением того, что они могут быть многомерными). Приведенный выше код дает одномерный массив, поэтому вы можете получить нужное значение x_sx с помощью maxima[0]

Ответ №2:

Помимо использования rec.x_sx вместо getattr() этого, мне кажется, что это очень удобочитаемое решение.

Если вы определенно хотите избавиться от четырех списков, вы можете создать один большой цикл, в котором вы отслеживаете наименьшее / наибольшее значение желаемого свойства (x_sx, …) и прямоугольник, к которому он принадлежит.

 min_x_sx = 1000  # a very big number. 
                 # tracking max values in a list requires starting with a very small number
min_x_sx_rectangle = None
# for the other three corners as well
for rec in rectangles:
    if rec.x_sx < min_x_sx:
        min_x_sx_rectangle = rec
        min_x_sx = rec.x_sx
    # for the other three corners as well
 

Ответ №3:

min и max возьмите ключевую функцию, чтобы

 x_sx = (min(getattr(rec, 'x_sx') for rec in rectangles))
 

может быть записано как:

 from operator import attrgetter
x_sx = min(rectangles, key=attrgetter('x_sx')).x_sx
 

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

1. К сожалению, я не могу использовать внешние библиотеки. Я забыл упомянуть об этом в сообщении. Есть ли способ сделать это без оператора? Спасибо!

2. operator является частью Python, но вы, конечно, можете написать min(rectangle, key=lambda r:r.x_sx).x_sx , если хотите…