Я написал несколько строк кода, чтобы решить эту проблему, но профилировщик говорит, что это очень много времени. (используя построчное профилирование Kernprof). Вот код:

comp = [1, 2, 3] #comp is list with always 3 elements, values 1, 2, 3 are just for illustration
m = max(comp)
max_where = [i for i, j in enumerate(comp) if j == m]
if 0 in max_where: 
    some action1
if 1 in max_where: 
    some action2
if 2 in max_where: 
    some action3

Профилировщик говорит, что большая часть времени расходуется на вычисление max_where. Я также попытался разбить этот расчет на if-дерево, чтобы избежать ненужных операций, но результаты не были удовлетворительными.

Пожалуйста, я делаю это неправильно или это просто питон?

1
Jendas 1 Фев 2013 в 16:04

5 ответов

Лучший ответ

Если это всегда три элемента, почему бы просто не сделать:

comp = [1, 2, 3] 
m = max(comp)

if comp[0] == m: 
    some action
if comp[1] == m: 
    some action
if comp[2] == m: 
    some action
3
Tobias Brandt 1 Фев 2013 в 12:17

Расширяя ответ Тобиаса, используя цикл for:

comp = [1, 2, 3] 
m = max(comp)

for index in range(len(comp)):
    if comp[index] == m:
        # some action

Поскольку индексация начинается с 0, вам не нужно делать len(comp) + 1. Я предпочитаю использовать индексирование в цикле for вместо реального элемента, потому что это значительно ускоряет процесс. Иногда в процессе вам может понадобиться индекс определенного элемента. Тогда использование l.index(obj) приведет к потере времени (даже если только незначительные суммы - для более длительных процессов это становится утомительным).

Это также предполагает, что каждый процесс (для comp[index]) очень похож: один и тот же процесс, но с разными переменными. Это не будет работать, если у вас есть существенно разные процессы для каждого индекса.

Однако, используя for index in range(len(l)):, у вас уже есть индекс, и к элементу можно легко получить доступ с помощью l[index] (вместе с индексом, который задается циклом).

Как ни странно, кажется, что реализация Тобиаса быстрее (я думал иначе):

comp = [1, 2, 3]
m = max(comp)
from timeit import timeit
def test1():
    if comp[0] == m: return m
    if comp[1] == m: return m
    if comp[2] == m: return m

def test2():
    for index in range(len(comp)):
        if comp[index] == m: return m

print 'test1:', timeit(test1, number = 1000)
print 'test2:', timeit(test2, number = 1000)

Возврат:

test1: 0.00121262329299
test2: 0.00469034990534

Моя реализация может быть быстрее для длинных списков (хотя не уверен). Тем не менее, написание кода для этого утомительно (для длинного списка с использованием повторных if comp[n] == m).

1
Rushy Panchal 1 Фев 2013 в 15:52

Если вы делаете это много раз, и если у вас есть все списки, доступные одновременно, то вы можете используйте из numpy.argmax для получения индексов для всех списков.

3
Michael J. Barber 1 Фев 2013 в 12:20

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

Тем не менее, есть небольшая оптимизация, о которой я могу подумать - это использование set, а не list понимания для max_where. Это сделает ваши три членских теста быстрее.

max_where = {i for i, j in enumerate(comp) if j == m}

Тем не менее, только с тремя пунктами / проверками, создание набора может занять больше времени, чем экономит.

В общем случае со списком из трех элементов эта операция займет незначительное количество времени. В моей системе для выполнения этой операции требуется половина микросекунды .

Вкратце: Не беспокойтесь. Если это не доказанное узкое место в вашей программе, для ускорения которого нужно , ваш текущий код в порядке.

2
Gareth Latty 1 Фев 2013 в 12:21

Как насчет этого:

sample = [3,1,2]    
dic = {0:func_a,1:func_b,2:func_c}
x = max(sample) 
y = sample.index(x)
dic[y]

Как упомянуто и справедливо понижено, это не работает для многократных вызовов функций. Однако это делает:

sample = [3,1,3]    
dic = {0:"func_a",1:"func_b",2:"func_c"}
max_val = max(sample) 
max_indices = [index for index, elem in enumerate(sample) if elem==max_val]
for key in max_indices:
    dic[key]

Это очень похоже на другие решения выше. Я знаю, что прошло некоторое время, но это было неправильно. :)

Ура!

1
SaCry 18 Фев 2013 в 15:40