#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
, если хотите…