Я ищу способ определить, хранят ли два списка одинаковые значения в одном и том же циклическом порядке, но начальная точка этого порядка может различаться между двумя списками.
Когда я говорю о циклическом упорядочении, я имею в виду, что последний элемент списка можно рассматривать как элемент непосредственно перед первым элементом списка.
Например:
['foo', 'bar', 'baz'] == ['bar', 'baz', 'foo']
>>> True
Это должно вывести True
, потому что 'foo' находится перед 'bar', который стоит перед 'baz' по кругу для обоих списков.
['foo', 'bar', 'baz'] == ['bar', 'foo', 'baz']
>>> False
Это должно вывести False
, потому что значения в списке не в том же порядке, независимо от того, сколько раз вы вращаете любой список.
Имея два списка, сначала утверждаем, что их длины равны. Если это не так, вам не нужно проверять элементы списка — отношение равенства не может выполняться.
Если они имеют одинаковую длину, создайте новый список, который будет первым списком, объединенным сам с собой. Если два списка циклически равны, то второй список будет подсписком первого списка, объединенным сам с собой.
Итак, мы можем сделать следующее:
def is_circular_equal(first, second):
if len(first) != len(second):
return False
repeated_first = first + first
for start_idx in range(len(first)):
if repeated_first[start_idx:start_idx + len(first)] == second:
return True
return False
Если списки короткие, то вы можете просто сделать копию второго списка и повернуть ее так, чтобы первое слово первого списка стало первым словом второго списка, а затем сравнить два списка. Вращение списка просто с нарезкой.
Однако, если списки очень длинные, создание нового списка может оказаться слишком неэффективным. Этот простой цикл позволяет избежать копирования:
def cmp_ring(lst1, lst2):
if len(lst1) != len(lst2):
return False
# For each occurrence of lst1[0] in lst2...
for start in [idx for idx,val in enumerate(lst2) if val == lst1[0]]:
for i in range(len(lst1)):
if lst1[i] != lst2[(i + start) % len(lst2)]:
break
else:
return True
return False
Для полноты, вот метод, упомянутый в первом абзаце:
def cmp_ring(lst1, lst2):
if len(lst1) != len(lst2): return False
for start in [idx for idx,val in enumerate(lst2) if val == lst1[0]]:
if lst1 == lst2[start:] + lst2[:start]: return True
return False
Хорошая точка зрения. Обновлено для обработки повторов.
не работают, когда значения повторяются в списке. Ваша функция возвращает false в этом примере: lst1 = ['a', 'a', 'b', 'c', 'b', 'b', 'b', 'a', 'c'], lst2 = ['а', 'с', 'а', 'а', 'б', 'с', 'б', 'б', 'б']