Имея список L в Python и два элемента x и y, которые гарантированно находятся в L, я хочу знать, появляется ли x перед y в L.
Если пара только одна, я могу просто перебирать L, пока не найду либо x, либо y. Это занимает время, линейное по длине L. Но мне приходится отвечать на множество таких запросов на один и тот же L (на разные x и y). Есть ли эффективный способ, например, структура данных или итератор в Python, который я могу использовать для быстрого ответа на множество запросов по одному и тому же L?
классический компромисс между временем и пространством: в линейном времени выполните один проход по списку, найдите и сохраните индекс первого появления каждого уникального элемента.





Когда гарантировано, что элемент будет найден в L только один раз, вы можете использовать простой словарь, который сопоставляет каждый элемент с его индексом. Однако если элемент может появляться несколько раз, для него требуются два словаря: один для хранения первого появления элемента, а другой — для хранения последнего.
L = ["n", "s", "t", "r", "i", "n", "g", "r"]
elem2index_first = {}
elem2index_last = {}
for index, elem in enumerate(L):
if elem not in elem2index_first: # Only update on the first occurrence
elem2index_first[elem] = index
elem2index_last[elem] = index # Overwrite on whatever the previous index was
Затем для каждого запроса требуется среднее значение постоянной сложности времени, поскольку для этого требуется всего два поиска в словаре.
print(elem2index_first[x] < elem2index_last[y]) # x comes before y
Для этого есть метод: elem2index_first.setdefault(elem, index) (заменяет две строки).
Как было предложено в ответе Долмока, вы можете использовать две индексные карты и выполнить поиск.
xs = ["p", "x", "k", "j", "p", "y", "x", "l"]
n = len(xs)
last_seen = dict(zip(xs, range(n)))
first_seen = dict(zip(reversed(xs), range(n - 1, -1, -1)))
is_x_before_y = first_seen['x'] < last_seen['y']
assert is_x_before_y
def ensure_x_bfr_y(L, xy):
xy = list(xy)
#Declare empty dict
dct = {}
# Iterate thru xy
for x in xy:
#Find the index of x and create a sublist of elements after x
x_idx = L.index(x[0])
sub = L[x_idx+1:]
if x[1] in sub:
dct[x] = True
else:
dct[x] = False
return dct
L = [23, 44, 11, 89, 65, 40, 71, 84,11]
xy = (23, 71), (89, 84), (40, 23), (65, 11)
r = ensure_x_bfr_y(L,xy)
print(r) # Output : {(23, 71): True, (89, 84): True, (40, 23): False, (65, 11): True}
Почему мой ответ отклонен?
Этот код работает не во всех случаях. Например, расширите свой список L значением 11. Таким образом, 65 появляется перед 11, но ваш вывод будет указывать, что это не так.
@SIGHUP, Спасибо за ответ. Я соответствующим образом отредактировал свой ответ. Пожалуйста, проверьте.
Могут ли x или y встречаться в L более одного раза или является L (фактически) множеством?