Checking if list is a sublist
Question:
I need to check if list1 is a sublist of list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)
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
Can anybody help me… why isn’t this working?
Answers:
i need to check if list1 is a sublist to list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)
Your code isn’t working because as soon as a list element in ls1 doesn’t occur in ls2 it will return False immediately.
This creates two lists that contain only the common elements (but in their original order) and then returns True when they are the same:
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: A memory-efficient variant:
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
Another way that we do this is with collections.Counter
. @L3viathan’s second answer is the most efficient and fastest way to do it.
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
His 2nd way is faster by an order of magnitude, but I wanted to mention the Counter variant because of its prevalence and usage outside of this scenario.
An easy way to check if all elements of a list are in other one is converting both to sets:
def sublist(lst1, lst2):
return set(lst1) <= set(lst2)
Another easy way is to use list comprehension
And use the built-in function all to verify that all items in list1 are contained in list2.
Example:
list1 = ['1','2']
list2 = ['1','2',3]
all(i in list2 for i in list1)
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
I found the above all found [‘a’,’b’,’d’] to be a sublist of [‘a’,’b’,’c’,’e’,’d’], which may not be true in spite of all of the elements of the sublist being present in the list. So to maintain the order and I came up with:
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
Whilst this isn’t very memory efficient, I find it works quite well with small lists.
Memory efficient solution based on M. Morgan’s answer. Takes into consideration that in order to be a sublist, the sublist must be found in the same order in the super list.
Variable k
keeps track of the length of matched characters. When this matches the length of our sublist we can return true.
Variable s
keeps track of the starting value. I keep track of this so that a test case like sublist(["1", "1", "2"],["0", "1", "1", "1", "2", "1", "2"])
with extraneous repeats of the first entry don’t affect the current index reset when unmatched. Once the starting value changes s
becomes irrelevant so this case does not fire in the middle of a pattern.
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
Its easy with iterators.
>>> 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
Try this one!! sublist y is not missing the sequence of list x.
x= list
y= sublist
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")
b = sublist
and a = list
then search b by splitting a in lengths of b
e.g.
>>> 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
I have come up with a short way to check for sublist
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))
what I have done is basically take 2 lists lst1 is the larger list and lst2 is the sublist that we are checking for.
then I am taking each element of the lst2 and checking if it is in the lst1 by looking for its index
if it can’t find even a single item it ..returns False
if all the items are covered it returns True
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)))
This passes @L3viathan’s doctest with fewer lines of code, using a similar strategy to the “memory-efficient variant”, and with arguably greater overall efficiency.
>>> 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
I used the intersection set instead of a generator because I think the extra memory is a good tradeoff compared to the time cost of shortcut-scanning the entire list per element (what in
does to a list), especially if they are long.
I also don’t think this should be called a “sublist” since xs
is allowed to have elements that ys
does not. The above relation is symmetric: swapping the arguments doesn’t change the answer. A real ordered “sublist” would not be symmetric and look more like this
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)))
Another way is to move through all possible sublists and return once a match was found
def is_sublist(ys, xs):
for i in range(len(xs) - len(ys)):
if xs[i:i + len(ys)] == ys:
return True
return False
#list1 = ['1','2',"4"]############works
#list2 = ['1','2',3]
lst2 = [4,8,9,33,44,67,123]
lst1 = [8,33,7] # works!
def sublist(lst1, lst2):
'checks whether list lst1 is a sublist of list lst2'
index1 = 0 # lst1 index
index2 = 0 # lst2 index
# go through indexes of lst1
while index1 < len(lst1):
# search for item in lst2 matching item in lst1 at index index1
while index2 < len(lst2) and lst1[index1] != lst2[index2]:
index2 += 1
# if we run out of items in lst2, lst1 is not a sublist of lst2
if index2 == len(lst2):
return False
index1 += 1
# every item in lst1 has been matched to an item in lst2, from left to right
return True
print( sublist(lst1, lst2))
I needed to know if the first list is the sub-list of the second one. This order was important to me. I’ve tried some of the solutions, but they are too ‘generic’ for my needs. I also wanted to make sure, that both lists are not equal. Here’s the solution.
def sublist(lst1, lst2):
len1 = len(lst1)
len2 = len(lst2)
if len1 >= len2:
return False
for i in range(0, len1):
if lst1[i] != lst2[i]:
return False
return True
Find in l1 all indexes where the element match with the first element in l2, then I loop over this indexes list and for each element get the slice of l1 with the same length of l2. If the l1 slice is equal to l2, then l2 is a sublist of l1
Ex:
l1 = [1,2,3,2,1,1,3,3,4,5]
l2 = [2,1,1,3,3]
True
l1 = [1,2,3,2,1,3,3,4,5]
l2 = [2,1,1,3,3]
False
def is_sublist(l1, l2):
index_list = [i for i, v in enumerate(l1) if v==l2[0]]
for ii in index_list:
l1_slice = l1[ii:ii+len(l2)]
if l1_slice == l2:
return True
else:
return False
what’s wrong with the following:
def sublist(lst1, lst2):
return all([(x in lst2) for x in lst1])
will return true if for all items in lst1, each item exists in lst2
How about just using an index that runs along list2 as we do the comparison?
def is_ordered_sublist(lst1: list, lst2: list) -> bool:
""" Checks if lst1 is an ordered sublist of lst2 """
try:
index = 0
for item in lst1:
location = lst2[index:].index(item)
index += location + 1
return True
except ValueError:
return False
Basically for each item in list1 it simply finds the first index which it appears in the second list. Thereafter it only needs to consider the remaining parts of list2. So the worse case complexity is simple O(len(list2)).
This code attempts to find list1 in list2 by by scanning list2. It searches list2 for the first item in list1 and then checks to see if successive items in list1 also match at the location in list2 where the first item is found. If the the first 2/4 items in list1 match at a location in list2 but the 3rd does not then it will not spend time comparing the 4th.
def ordered_sublist(l1, l2):
length = len(l1)
for i in range(len(l2) - length + 1):
if all(l1[j] == l2[j + i] for j in range(length)):
return True
return False
def lis1(item,item1):
sub_set = False
for x in range(len(item)):
if item[x] == item1[0]:
n = 1
while (n < len(item1) and (item[x + n] == item1[1])):
n += 1
if n == len(item1):
return True
return False
a = [2,3,4,5,6]
b = [5,6]
c = [2,7,6]
print(lis1(a,b))
print(lis1(a,c))
I think this is the best way to solve this problem. This will check if list1
is a sublist of list2
. We will assume that all elements are unique. If we have duplicate elements the following code will only ensure that each element of list1
is contained in list2
. Hence, we do not take multiplicity into account.
list1 = [2, 3, 3, 4, 5, 9]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
set(list1).issubset(set(list2))
Lists are data structures where the order of the elements matters.
I understand that this question explicitly specifies "same order of indexes" but in general, when you say "sublist", this is not necessarily the only restriction that applies. The relative position between each element may also be a restriction.
In my particular case list1=[1,2,3,4] list2=[1,2,4] and list2 is not a sublist of list1, but list3=[2,3,4] is a sublist of list1.
Just for the sake of completion, I am posting here my code to find sublists where the relative index of each element also should be preserved.
def is_sublist(list1, list2):
first_index = -1
for i in range(len(list1)):
if first_index>=0:
j = i-first_index
if list1[i] != list2[j]:
return False
if j == len(list2)-1:
return True
elif list1[i] == list2[0]:
first_index = i
return False
print(is_sublist(['r1','r2','r3','r4','r6'],['r1','r2','r3']))
#>> True
print(is_sublist(['r1','r2','r3','r4','r6'],['r2','r3','r4']))
#>> True
print(is_sublist(['r1','r2','r3','r4','r6'],['r1','r2','r4']))
#>> False
Definition:
- List A is a sublist of list B if the exact sequence of elements of A exists in B.
- An empty list is a sublist of any list.
The following function returns the index of the first occurrence of list_a
in list_b
, otherwise -1
is returned. For empty list_a
, 0
is returned.
def sublist(list_a, list_b):
if 0 == len(list_a):
return 0
if len(list_b) < len(list_a):
return -1
idx = -1
while list_a[0] in list_b[idx+1:]:
idx = list_b.index(list_a[0], idx + 1)
if list_a == list_b[idx:idx+len(list_a)]:
return idx
return -1
Some tests:
>>> sublist([], [])
0
>>> sublist([], [1, 2, 3])
0
>>> sublist([3, 6], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
2
>>> sublist([3, 7, 9, 8], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
4
>>> sublist([3, 6, 3, 7, 9, 8, 0, 3, 6], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
2
>>> sublist([1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6, 4], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
-1
>>> sublist([3, 7, 4], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
-1
Here’s a lazy-iteration, generic version for checking whether an iterable is a subsequence of another iterable:
from typing import Iterable
def is_subsequence(a: Iterable, b: Iterable) -> bool:
b_iterator = iter(b)
for x in a:
for y in b_iterator:
if y == x:
break
else:
return False
else:
return True
I need to check if list1 is a sublist of list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)
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
Can anybody help me… why isn’t this working?
i need to check if list1 is a sublist to list2 (True; if every integer in list2 that is common with list1 is in the same order of indexes as in list1)
Your code isn’t working because as soon as a list element in ls1 doesn’t occur in ls2 it will return False immediately.
This creates two lists that contain only the common elements (but in their original order) and then returns True when they are the same:
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: A memory-efficient variant:
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
Another way that we do this is with collections.Counter
. @L3viathan’s second answer is the most efficient and fastest way to do it.
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
His 2nd way is faster by an order of magnitude, but I wanted to mention the Counter variant because of its prevalence and usage outside of this scenario.
An easy way to check if all elements of a list are in other one is converting both to sets:
def sublist(lst1, lst2):
return set(lst1) <= set(lst2)
Another easy way is to use list comprehension
And use the built-in function all to verify that all items in list1 are contained in list2.
Example:
list1 = ['1','2']
list2 = ['1','2',3]
all(i in list2 for i in list1)
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
I found the above all found [‘a’,’b’,’d’] to be a sublist of [‘a’,’b’,’c’,’e’,’d’], which may not be true in spite of all of the elements of the sublist being present in the list. So to maintain the order and I came up with:
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
Whilst this isn’t very memory efficient, I find it works quite well with small lists.
Memory efficient solution based on M. Morgan’s answer. Takes into consideration that in order to be a sublist, the sublist must be found in the same order in the super list.
Variable k
keeps track of the length of matched characters. When this matches the length of our sublist we can return true.
Variable s
keeps track of the starting value. I keep track of this so that a test case like sublist(["1", "1", "2"],["0", "1", "1", "1", "2", "1", "2"])
with extraneous repeats of the first entry don’t affect the current index reset when unmatched. Once the starting value changes s
becomes irrelevant so this case does not fire in the middle of a pattern.
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
Its easy with iterators.
>>> 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
Try this one!! sublist y is not missing the sequence of list x.
x= list
y= sublist
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")
b = sublist
and a = list
then search b by splitting a in lengths of b
e.g.
>>> 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
I have come up with a short way to check for sublist
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))
what I have done is basically take 2 lists lst1 is the larger list and lst2 is the sublist that we are checking for.
then I am taking each element of the lst2 and checking if it is in the lst1 by looking for its index
if it can’t find even a single item it ..returns False
if all the items are covered it returns True
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)))
This passes @L3viathan’s doctest with fewer lines of code, using a similar strategy to the “memory-efficient variant”, and with arguably greater overall efficiency.
>>> 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
I used the intersection set instead of a generator because I think the extra memory is a good tradeoff compared to the time cost of shortcut-scanning the entire list per element (what in
does to a list), especially if they are long.
I also don’t think this should be called a “sublist” since xs
is allowed to have elements that ys
does not. The above relation is symmetric: swapping the arguments doesn’t change the answer. A real ordered “sublist” would not be symmetric and look more like this
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)))
Another way is to move through all possible sublists and return once a match was found
def is_sublist(ys, xs):
for i in range(len(xs) - len(ys)):
if xs[i:i + len(ys)] == ys:
return True
return False
#list1 = ['1','2',"4"]############works
#list2 = ['1','2',3]
lst2 = [4,8,9,33,44,67,123]
lst1 = [8,33,7] # works!
def sublist(lst1, lst2):
'checks whether list lst1 is a sublist of list lst2'
index1 = 0 # lst1 index
index2 = 0 # lst2 index
# go through indexes of lst1
while index1 < len(lst1):
# search for item in lst2 matching item in lst1 at index index1
while index2 < len(lst2) and lst1[index1] != lst2[index2]:
index2 += 1
# if we run out of items in lst2, lst1 is not a sublist of lst2
if index2 == len(lst2):
return False
index1 += 1
# every item in lst1 has been matched to an item in lst2, from left to right
return True
print( sublist(lst1, lst2))
I needed to know if the first list is the sub-list of the second one. This order was important to me. I’ve tried some of the solutions, but they are too ‘generic’ for my needs. I also wanted to make sure, that both lists are not equal. Here’s the solution.
def sublist(lst1, lst2):
len1 = len(lst1)
len2 = len(lst2)
if len1 >= len2:
return False
for i in range(0, len1):
if lst1[i] != lst2[i]:
return False
return True
Find in l1 all indexes where the element match with the first element in l2, then I loop over this indexes list and for each element get the slice of l1 with the same length of l2. If the l1 slice is equal to l2, then l2 is a sublist of l1
Ex:
l1 = [1,2,3,2,1,1,3,3,4,5]
l2 = [2,1,1,3,3]
True
l1 = [1,2,3,2,1,3,3,4,5]
l2 = [2,1,1,3,3]
False
def is_sublist(l1, l2):
index_list = [i for i, v in enumerate(l1) if v==l2[0]]
for ii in index_list:
l1_slice = l1[ii:ii+len(l2)]
if l1_slice == l2:
return True
else:
return False
what’s wrong with the following:
def sublist(lst1, lst2):
return all([(x in lst2) for x in lst1])
will return true if for all items in lst1, each item exists in lst2
How about just using an index that runs along list2 as we do the comparison?
def is_ordered_sublist(lst1: list, lst2: list) -> bool:
""" Checks if lst1 is an ordered sublist of lst2 """
try:
index = 0
for item in lst1:
location = lst2[index:].index(item)
index += location + 1
return True
except ValueError:
return False
Basically for each item in list1 it simply finds the first index which it appears in the second list. Thereafter it only needs to consider the remaining parts of list2. So the worse case complexity is simple O(len(list2)).
This code attempts to find list1 in list2 by by scanning list2. It searches list2 for the first item in list1 and then checks to see if successive items in list1 also match at the location in list2 where the first item is found. If the the first 2/4 items in list1 match at a location in list2 but the 3rd does not then it will not spend time comparing the 4th.
def ordered_sublist(l1, l2):
length = len(l1)
for i in range(len(l2) - length + 1):
if all(l1[j] == l2[j + i] for j in range(length)):
return True
return False
def lis1(item,item1):
sub_set = False
for x in range(len(item)):
if item[x] == item1[0]:
n = 1
while (n < len(item1) and (item[x + n] == item1[1])):
n += 1
if n == len(item1):
return True
return False
a = [2,3,4,5,6]
b = [5,6]
c = [2,7,6]
print(lis1(a,b))
print(lis1(a,c))
I think this is the best way to solve this problem. This will check if list1
is a sublist of list2
. We will assume that all elements are unique. If we have duplicate elements the following code will only ensure that each element of list1
is contained in list2
. Hence, we do not take multiplicity into account.
list1 = [2, 3, 3, 4, 5, 9]
list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
set(list1).issubset(set(list2))
Lists are data structures where the order of the elements matters.
I understand that this question explicitly specifies "same order of indexes" but in general, when you say "sublist", this is not necessarily the only restriction that applies. The relative position between each element may also be a restriction.
In my particular case list1=[1,2,3,4] list2=[1,2,4] and list2 is not a sublist of list1, but list3=[2,3,4] is a sublist of list1.
Just for the sake of completion, I am posting here my code to find sublists where the relative index of each element also should be preserved.
def is_sublist(list1, list2):
first_index = -1
for i in range(len(list1)):
if first_index>=0:
j = i-first_index
if list1[i] != list2[j]:
return False
if j == len(list2)-1:
return True
elif list1[i] == list2[0]:
first_index = i
return False
print(is_sublist(['r1','r2','r3','r4','r6'],['r1','r2','r3']))
#>> True
print(is_sublist(['r1','r2','r3','r4','r6'],['r2','r3','r4']))
#>> True
print(is_sublist(['r1','r2','r3','r4','r6'],['r1','r2','r4']))
#>> False
Definition:
- List A is a sublist of list B if the exact sequence of elements of A exists in B.
- An empty list is a sublist of any list.
The following function returns the index of the first occurrence of list_a
in list_b
, otherwise -1
is returned. For empty list_a
, 0
is returned.
def sublist(list_a, list_b):
if 0 == len(list_a):
return 0
if len(list_b) < len(list_a):
return -1
idx = -1
while list_a[0] in list_b[idx+1:]:
idx = list_b.index(list_a[0], idx + 1)
if list_a == list_b[idx:idx+len(list_a)]:
return idx
return -1
Some tests:
>>> sublist([], [])
0
>>> sublist([], [1, 2, 3])
0
>>> sublist([3, 6], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
2
>>> sublist([3, 7, 9, 8], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
4
>>> sublist([3, 6, 3, 7, 9, 8, 0, 3, 6], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
2
>>> sublist([1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6, 4], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
-1
>>> sublist([3, 7, 4], [1, 2, 3, 6, 3, 7, 9, 8, 0, 3, 6])
-1
Here’s a lazy-iteration, generic version for checking whether an iterable is a subsequence of another iterable:
from typing import Iterable
def is_subsequence(a: Iterable, b: Iterable) -> bool:
b_iterator = iter(b)
for x in a:
for y in b_iterator:
if y == x:
break
else:
return False
else:
return True