Проверка списка подписок
Мне нужно проверить, является ли list1 подстрок list2 (True, если любое целое число в списке2, которое является общим с list1, находится в том же порядке индексов, что и в списке1)
def sublist(lst1,lst2):
for i in range(len(lst1)):
if lst1[i] not in lst2:
return False
for j in range(len(lst2)):
if (lst1[j] in lst2) and (lst2.index(lst1[i+1]) > lst2.index(lst1[i])):
return True
Может кто-нибудь мне помочь... почему это не работает?
Ответы
Ответ 1
Мне нужно проверить, является ли list1 подписок для list2 (True, если любое целое число в списке2, которое является общим с list1, находится в том же порядке индексов, что и в списке1)
Ваш код не работает, потому что, как только элемент списка в ls1 не встречается в ls2, он немедленно вернет False.
Это создает два списка, которые содержат только общие элементы (но в их первоначальном порядке), а затем возвращает True, когда они одинаковы:
def sublist(lst1, lst2):
ls1 = [element for element in lst1 if element in lst2]
ls2 = [element for element in lst2 if element in lst1]
return ls1 == ls2
edit: Вариант с эффективностью памяти:
def sublist(ls1, ls2):
'''
>>> sublist([], [1,2,3])
True
>>> sublist([1,2,3,4], [2,5,3])
True
>>> sublist([1,2,3,4], [0,3,2])
False
>>> sublist([1,2,3,4], [1,2,5,6,7,8,5,76,4,3])
False
'''
def get_all_in(one, another):
for element in one:
if element in another:
yield element
for x1, x2 in zip(get_all_in(ls1, ls2), get_all_in(ls2, ls1)):
if x1 != x2:
return False
return True
Ответ 2
Другой способ, которым мы это делаем, - collections.Counter
. @L3viathan второй ответ - самый эффективный и быстрый способ сделать это.
def sublist1(lst1, lst2):
ls1 = [element for element in lst1 if element in lst2]
ls2 = [element for element in lst2 if element in lst1]
return ls1 == ls2
def sublist2(lst1, lst2):
def get_all_in(one, another):
for element in one:
if element in another:
yield element
for x1, x2 in zip(get_all_in(lst1, lst2), get_all_in(lst2, lst1)):
if x1 != x2:
return False
return True
def sublist3(lst1, lst2):
from collections import Counter
c1 = Counter(lst1)
c2 = Counter(lst2)
for item, count in c1.items():
if count > c2[item]:
return False
return True
l1 = ["a", "b", "c", "c", "c", "d", "e"]
l2 = ["c", "a", "c", "b", "c", "c", "d", "d", "f", "e"]
s1 = lambda: sublist1(l1, l2)
s2 = lambda: sublist2(l1, l2)
s3 = lambda: sublist3(l1, l2)
from timeit import Timer
t1, t2, t3 = Timer(s1), Timer(s2), Timer(s3)
print(t1.timeit(number=10000)) # => 0.034193423241588035
print(t2.timeit(number=10000)) # => 0.012621842119714115
print(t3.timeit(number=10000)) # => 0.12714286673722477
Его второй способ быстрее на порядок, но я хотел упомянуть вариант Counter из-за его распространенности и использования вне этого сценария.
Ответ 3
Простой способ проверить, находятся ли все элементы списка в другом, преобразовывая оба набора:
def sublist(lst1, lst2):
return set(lst1) <= set(lst2)
Ответ 4
Эффективное решение для памяти, основанное на ответе М. Моргана. Принимает во внимание, что для того, чтобы быть подписок, подсписок должен быть найден в том же порядке в супер-списке.
Переменная k
отслеживает длину совпадающих символов. Когда это соответствует длине нашего подсписок, мы можем вернуть true.
Переменная s
отслеживает начальное значение. Я отслеживаю это, так что тестовый пример типа sublist(["1", "1", "2"],["0", "1", "1", "1", "2", "1", "2"])
с посторонними повторами первой записи не влияет на текущий индекс reset, когда он не имеет аналогов. После изменения значения начального значения s
становится неуместным, поэтому этот случай не срабатывает в середине шаблона.
def sublist(sublist, lst):
if not isinstance(sublist, list):
raise ValueError("sublist must be a list")
if not isinstance(lst, list):
raise ValueError("lst must be a list")
sublist_len = len(sublist)
k=0
s=None
if (sublist_len > len(lst)):
return False
elif (sublist_len == 0):
return True
for x in lst:
if x == sublist[k]:
if (k == 0): s = x
elif (x != s): s = None
k += 1
if k == sublist_len:
return True
elif k > 0 and sublist[k-1] != s:
k = 0
return False
Ответ 5
b = sublist
и a = list
затем ищите b, разделив a на длины b
например
>>> a = [2,4,3,5,7] , b = [4,3]
>>> b in [a[i:len(b)+i] for i in xrange(len(a))]
True
>>> a = [2,4,3,5,7] , b = [4,10]
>>> b in [a[i:len(b)+i] for i in xrange(len(a))]
False
Ответ 6
Я нашел, что выше всего найдено ['a', 'b', 'd'] как подсписку ['a', 'b', 'c', 'e', 'd'], которое может быть неверным, несмотря на то, что все элементы подсписчика присутствуют в списке. Поэтому, чтобы поддерживать порядок, я придумал:
def sublist4(sublist,lst):
#Define an temp array to populate
sub_list=[]
comparable_sublist=[]
#Define two constants to iterate in the while loop
i=0
k=0
#Loop the length of lst
while i < len(lst):
#If the element is in the sublist append to temp array,
if k < len(sublist) and lst[i] == sublist[k]:
sub_list.append(lst[i])
#set a comparable array to the value of temp array
comparable_sublist = sub_list
k += 1
#If the comparable array is the same as the sublist, break
if len(comparable_sublist) == len(sublist):
break
#If the element is not in the sublist, reset temp array
else:
sub_list = []
i += 1
return comparable_sublist == sublist
Несмотря на то, что это не очень эффективно, я считаю, что он работает хорошо с небольшими списками.
Ответ 7
Легко с итераторами.
>>> a = [0,1,2]
>>> b = [item for item in range(10)]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
[0, 1, 2]
>>> [False, True][set([item in b for item in a]) == set([True])]
True
>>> a = [11, 12, 13]
>>> [False, True][set([item in b for item in a]) == set([True])]
False
Ответ 8
Еще один простой способ - использовать понимание списка
И используйте встроенную функцию all, чтобы убедиться, что все элементы в списке1 содержатся в списке2.
Пример:
list1 = ['1','2']
list2 = ['1','2',3]
all(i in list2 for i in list1)
Ответ 9
def sublist(l1,l2):
s1=" ".join(str(i) for i in l1)
s2=" ".join(str(i) for i in l2)
if s1 in s2:
return True
else:
return False
Ответ 10
Попробуй это!! В подсписке y не пропущена последовательность списка x.
х = список
у = подсписок
if ([i for i,j in enumerate(y) for k,l in enumerate(x) if i == k and j!=l]):
print("True")
else:
print("False")
Ответ 11
Я нашел короткий способ проверить список
lst1=[1,2,5,6,8,3,2,34,3,4]
lst2=[1,2,3,4]
def sublist(lst1,lst2):
for item in lst2:
try:
lst1.index(item)
except ValueError:
return False
return True
print(sublist(lst1,lst2))
В основном я взял 2 списка. lst1 - это большой список, а lst2 - это подсписок, который мы проверяем. затем я беру каждый элемент lst2 и проверяю, есть ли он в lst1, ища его индекс
если он не может найти ни одного предмета, он возвращается
если все элементы покрыты, возвращается True
Ответ 12
def has_ordered_intersection(xs, ys):
common = {*xs} & {*ys}
return all(x == y for x, y in zip((x for x in xs if x in common),
(y for y in ys if y in common)))
Это позволяет пройти тестирование @L3viathan с меньшим количеством строк кода, используя стратегию, аналогичную "эффективному по памяти варианту", и с возможно большей общей эффективностью.
>>> has_ordered_intersection([], [1,2,3])
True
>>> has_ordered_intersection([1,2,3,4], [2,5,3])
True
>>> has_ordered_intersection([1,2,3,4], [0,3,2])
False
>>> has_ordered_intersection([1,2,3,4], [1,2,5,6,7,8,5,76,4,3])
False
Я использовал пересечение установить вместо генератора, потому что я думаю, что дополнительная память является хорошим выбором по сравнению с временем стоимости контекстного сканированием всего списка для каждого элемента (что in
делает в список), особенно если они длинные.
Я также не думаю, что это следует называть "подсписком", так как xs
разрешено иметь элементы, которые не имеют ys
. Вышеуказанное соотношение симметрично: обмен аргументами не меняет ответ. Реальный упорядоченный "подсписок" не будет симметричным и будет выглядеть примерно так
def is_ordered_sublist(xs, ys):
xset = {*xs}
return all(x == y for x, y in zip(xs, (y for y in ys if y in xset)))
Ответ 13
Другой способ - просмотреть все возможные подсписки и вернуться после того, как найдено совпадение.
def is_sublist(ys, xs):
for i in range(len(xs) - len(ys)):
if xs[i:i + len(ys)] == ys:
return True
return False