Проверка подсписка в списке

Вопрос: вам нужно написать функцию с именем isSublist(), которая принимает два аргумента (list, sublist) и возвращает 1, если подсписок является подсписком списка, и 0 в противном случае.

Итак, у меня есть свой код, однако я получаю True, когда подсписка нет в списке. Любые предложения по исправлению этого, пожалуйста?

 def isSublist(list, sublist):
    for i in range(len(list)-(len(sublist))+1):
        return True
    if sublist==list[i:i+(len(sublist))]:
        return False

образец ввода:

list= (0,1,2,3,4,5,6,7,8,9)
isSublist(list, [1,2,3])
output:
True

person user2898221    schedule 14.11.2013    source источник
comment
Можете ли вы предоставить образец входных данных и ожидаемый результат? Когда вы говорите подсписок, вы имеете в виду [1,2,3] in [[1,2,3], [5,6,7]] или [1,2,3] in [1,2,3,4,5,6]?   -  person Steinar Lima    schedule 15.11.2013
comment
Пожалуйста, кратко определите, что вы подразумеваете под подсписком списка   -  person pkacprzak    schedule 15.11.2013
comment
А заказ считается? Хотели бы вы, чтобы для двух подсписков [1, 2, 3] и [2, 3, 1] выводился один и тот же результат?   -  person Steinar Lima    schedule 15.11.2013
comment
под списком я имею в виду, что в списке [1,2,3,4] есть подсписок [1,2] в списке. Если да, то выведите True, если не False   -  person user2898221    schedule 15.11.2013
comment
А как насчет sublist = [2, 1]? А если list = [1, 1, 2, 2, 3] и sublist = [1, 2, 3]?   -  person Steinar Lima    schedule 15.11.2013
comment
@SteinarLima подсписок не может быть в обратном порядке. подсписок должен отображаться в списке точно так же, как список   -  person user2898221    schedule 15.11.2013


Ответы (4)


Вы можете разбить это, получив все фрагменты размером с подсписок и сравнив равенство:

def n_slices(n, list_):
    for i in xrange(len(list_) + 1 - n):
        yield list_[i:i+n]

def isSublist(list_, sub_list):
    for slice_ in n_slices(len(sub_list), list_):
        if slice_ == sub_list:
            return True
    return False

Прикрыть вопрос заказа. Список по определению упорядочен. Если мы хотим игнорировать порядок, вы можете сделать наборы:

def isSubset(list_, sub_list):
    return set(sub_list) <= set(list_)

Если нам нужно покрыть повторяющиеся элементы и игнорировать порядок, вы теперь находитесь в области мультимножеств:

def isSubset(list_, sub_list):
    for item in sub_list:
        if sub_list.count(item) > list_.count(item):
            return False
    return True
person John Spong    schedule 15.11.2013
comment
Наборы имеют оператор <=, нет необходимости использовать объединение. return set(sub_list) <= set(list_) - person FogleBird; 15.11.2013

>>> def isSublist(originallist,sublist,biglist):
    if not sublist:
        return True
    if not biglist:
        return False
    if sublist[0]==biglist[0]:
        return isSublist(originallist,sublist[1:],biglist[1:]) or isSublist(originallist,sublist,biglist[1:])
    return isSublist(originallist,originallist,biglist[1:])

тестовый вывод:

>>> isSublist([1,2,4],[1,2,4],[1,2,3,4])
False
>>> isSublist([1,2,3],[1,2,3],[1,2,3,4])
True
>>> 

Отредактировано для подсписков, а не для подмножества. Уродливее, но работает. Можно добавить обертку, чтобы избежать путаницы параметров.

def sublist(a,b):
    isSublist(a,a,b)
person C.B.    schedule 15.11.2013
comment
isSublist([1, 2, 4], [1, 2, 3, 4]) возвращает True неправильно. - person FogleBird; 15.11.2013
comment
ОП не указал, важен ли порядок, поэтому вы не можете быть так уверены. - person Steinar Lima; 15.11.2013
comment
Подсписок, а не подмножество. Подмножество будет простым return set(sublist) <= set(list) - person FogleBird; 15.11.2013
comment
это подсписок, а не подмножество - person user2898221; 15.11.2013

Часть вашей проблемы заключается в том, что в Python(0,1,2,3,4,5,6,7,8,9)технически не alist, а atuple, который по сути является неизменным (неизменяемым)list. Кроме того, вы должны избегать называть вещи в своей программе так же, как встроенные функции и типы, потому что иногда вам нужно ссылаться на них, и ваше собственное определение будет скрывать имена, предоставленные системой.

Один простой способ обойти это — просто добавить an_ в конец имени, как это сделано в следующем примере, который пытается преобразовать аргумент в alist, если он изначально не был таковым. Он не проверяет тип аргумента thesublist, но подобная проверка может подойти и для него.

def isSublist(list_, sublist):
    if not isinstance(list_, list):
        list_ = list(list_)
    sublen = len(sublist)
    for i in xrange(len(list_)-sublen+1):
        if list_[i:i+sublen] == sublist:
            return True
    return False

list_ = (0,1,2,3,4,5,6,7,8,9)
print subfunc(list_, [0,1])  # --> True
print subfunc(list_, [1,2,3])  # --> True
print subfunc(list_, [4,6,7])  # --> False
print subfunc(list_, [4,5])  # --> True
person martineau    schedule 15.11.2013

Я только что написал рецепт для этого (это работает для непрерывного подсписка):

def is_sublist(sublist, superlist):  
    ''''' 
    Checks whether 'sublist' is a sublist of 'superlist'. 
    Both arguments must be typed list or tuple. 
    '''  
    if not isinstance(sublist, (list, tuple)) or not isinstance(sublist, (list,tuple)):  
        raise TypeError("Both 'sublist' and 'superlist' must be lists or tuples.")  
    # Return early if candidate sublist is longer than superlist  
    if len(sublist) > len(superlist):  
        return False  
    else:  
        for chunk in (superlist[i:i+len(sublist)] for i in range(0, len(superlist)-len(sublist)+1)):   
            if chunk == sublist:  
                return True  
        return False

Идея состоит в том, чтобы смещающееся окно (имеющее ту же ширину, что и подсписок кандидатов) сканировало суперсписок и проверяло равенство между фрагментом и подсписком на каждой итерации.

Это метод грубой силы.

person Olivier H    schedule 25.08.2016
comment
Извините, я не видел исходную дату публикации и все существующие ответы. Я оставлю свой ответ, так как его синтаксис и проверка типов немного отличаются от других ответов. - person Olivier H; 25.08.2016