try:
last_found = -1
for num in L1:
last_found = L2.index(num, last_found + 1)
return True
except ValueError:
return False
index
метод списка L2 возвращает позицию, в которой первый аргумент (num
) находится в списке; называется, как здесь, со вторым аргументом, он начинает искать в списке в этой позиции. Если index
не находит то, что он ищет, он вызывает исключение ValueError
.
Таким образом, этот код использует этот подход для поиска каждого элемента num
от L1
, на заказ, внутри L2
. В первый раз ему нужно начать смотреть с позиции 0; каждый последующий момент времени, он должен начать смотреть с позиции сразу после последней, где он нашел предыдущий элемент, то есть last_found + 1
(поэтому в начале мы должны установить last_found = -1
, чтобы начать смотреть с позиции 0 в первый раз).
Если каждый элемент в L1 найден таким образом (то есть он найден в L2 после позиции, где был найден предыдущий элемент), то два списка удовлетворяют заданному условию, а код возвращает True
. Если какой-либо элемент L1 когда-либо не найден, код ловит результирующее исключение ValueError
и просто возвращает False
.
Другой подход заключается в использовании итераторов над двумя списками, которые могут быть сформированы с помощью встроенной функции iter
. Вы можете «продвигать» итератор, вызывая встроенный next
; это повысит StopIteration
, если нет «следующего элемента», то есть итератор исчерпан. Вы также можете использовать for
на итераторе для более гладкого интерфейса, где это применимо. Подход низкого уровня с использованием ИТЭР/следующая идея:
i1 = iter(L1)
i2 = iter(L2)
while True:
try:
lookfor = next(i1)
except StopIteration:
# no more items to look for == all good!
return True
while True:
try:
maybe = next(i2)
except StopIteration:
# item lookfor never matched == nope!
return False
if maybe == lookfor:
break
или немного выше уровня:
i1 = iter(L1)
i2 = iter(L2)
for lookfor in i1:
for maybe in i2:
if maybe == lookfor:
break
else:
# item lookfor never matched == nope!
return False
# no more items to look for == all good!
return True
В самом деле, единственным важным использование iter
здесь, чтобы получить i2 - с внутренним контуром, поскольку for maybe in i2
гарантирует, что внутренний цикл не будет начинать смотреть с самого начала каждый раз, но, скорее, он будет продолжать смотреть, где он последний раз. Внешний цикл может также использоваться для for lookfor in L1:
, так как он не имеет проблемы с перезапуском.
Ключ, здесь - этопредложение циклов, которое срабатывает, если и только если цикл не был прерван break
, а скорее естественным путем.
Работая над этой идеей, нам снова напомнили о операторе in
, который также можно использовать для продолжения, где он в последний раз оставался простым использованием итератора. Большое упрощение:
i2 = iter(L2)
for lookfor in L1:
if lookfor not in i2:
return False
# no more items to look for == all good!
return True
Но теперь мы понимаем, что это именно скороговоркой абстрагируется от коротких замыкания any
и all
встроенных «короткого замыкания аккумулятора» функции, так что ...:
i2 = iter(L2)
return all(lookfor in i2 for lookfor in L1)
, который, я считаю, почти так же прост, как вы можете получить.Единственный неэлементарный бит, оставшийся здесь, - это то, что вы должны использовать только iter(L2)
, только один раз, чтобы убедиться, что оператор in
(по сути внутренний цикл) не перезапускает поиск с самого начала, а скорее продолжает каждый раз, откуда последний раз.
Ваша идея сравнения значений индекса будет работать, только если значения 'list2' уникальны. Например, рассмотрим, был ли 'list2'' '[5,2,3,4,1,5]' –