Относительный порядок элементов в списке

Я пишу функцию, которая принимает список чисел и возвращает список из относительно позиционированных элементов.

то есть, если мой вход в указанную функцию [1, 5, 4] выход будет [0, 2, 1], так как 1 является самым низким элементом, 5 является самым высоким и 4 в середине, все элементы являются уникальными значениями или set ()

но код говорит, функция, которую я до сих пор

def relative_order(a):
    rel=[]
    for i in a:
        loc = 0
        for v in a:
            if i > v:
                loc += 1
        rel.append(loc)
    return rel

это работает, но поскольку я отправляю большие списки в эту функцию, и я должен сравнить каждый элемент со всеми элементами в каждой итерации, это занимает ~5sec со списком 10.000 элементов.

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

5 ответов


Это можно записать как понимание списка, как это:

lst = [1, 5, 4]
s = sorted(lst)    
[s.index(x) for x in lst]
=> [0, 2, 1]

и вот еще один тест, используя пример @frb:

lst = [10, 2, 3, 9]
s = sorted(lst)    
[s.index(x) for x in lst]
=> [3, 0, 1, 2]

вот еще один ход, который должен быть более эффективным, чем сохранение .index ' ing в список, как указано, что не будет повторяющихся значений, поэтому мы можем сделать поиск O (1) вместо линейного... (и фактически отвечает требованиям):

>>> a = [10, 2, 3, 9]
>>> indexed = {v: i for i, v in enumerate(sorted(a))}
>>> map(indexed.get, a)
[3, 0, 1, 2]

метод, который у вас есть, и текущий ответ занимает порядок N^2 времени.

Это должно работать в log (n) time:

def relative_order(a):
    positions = sorted(range(len(a)), key=lambda i: a[i])
    return sorted(range(len(a)), key = lambda i: positions[i])

это все еще журнал заказов (n), и поэтому он должен работать и для ваших больших списков.

изменить:

за пределами лямбда.


def relative_order(a):
    l = sorted(a)
    # hash table of element -> index in ordered list
    d = dict(zip(l, range(len(l))))
    return [d[e] for e in a]

print relative_order([1, 5, 4])
print relative_order([2, 3, 1])
print relative_order([10, 2, 3, 9])

[0, 2, 1]
[1, 2, 0]
[3, 0, 1, 2]

алгоритм должен быть таким же эффективным, как сортировка, но использовать дополнительное пространство.


Ваш вопрос о сортировке. Я бы рекомендовал использовать Numpy или "числовой Python". Numpy-это модуль Python, оптимизированный для "быстрого, компактного, многомерного массива". Это пакет для научных вычислений на Python. http://www.numpy.org/

import numpy as np

input_array = np.array([1, 5, 4])
sorted_indices = np.argsort(input_array)

print sorted_indices
#[0 2, 1]

Я также добавил вывод профилировщика на основе массива size 50000. Он показывает, что этот метод (около 4x) быстрее, чем использование Python