Решение, действует ли список как подсписок другого списка

1

Я немного поработал над этой проблемой и просто чувствую себя полностью потерянным. Похоже, это было бы очень фундаментально, но, похоже, не могло его решить. Я на самом деле не ищу точного ответа, скорее, если я на правильном пути. Я только что закончил свою 3-ей неделю введения в программирование, поэтому я уверен, что некоторые форматирования немного завораживают, поэтому извините.

Я пытаюсь определить функцию, которая может принимать два списка: list1 и list2 и посмотреть, будет ли list1 служить подписок для list2 а также учитывать порядок.

Например, в книге вопрос гласит:

Если list1 определяется как: [15, 1, 100]

и list2 определяется как: [20, 15, 30, 50, 1, 100]

то list1 является подсписком list2 потому что числа в list1 (15, 1 и 100) отображаются в list2 в том же порядке.

Однако list [15, 50, 20] не является списком list2 потому что порядок не совпадает.

Я не уверен, что я пойду правильно, но я хотел бы добавить то, что у меня есть до сих пор, и хотел бы, чтобы на него было высказано мнение. Я добавил комментарии, чтобы дать немного больше информации о моем мыслительном процессе.



l1 = eval(input('\nPlease enter a list of integers: '))
l2 = eval(input('\nPlease enter a second list of integers: '))

def subList(l1, l2):
    'Takes two lists as input from the user and determines'
    'True if list1 is a sublist of list2 and false otherwise.'

    newLst = []
    indexNum = 0
    result = subList(l1, l2)

    if len(l1) > len(l2):
        return False
    elif l1 == []:
        return True

    for num in l1:

        #My thinking here is that this while loop should run for as long     as ther variable indexNum
        #Doesn't exceed the length of lst2, allowing me to compare every num of lst1 with that of lst2
        while indexNum < len(l2):

            #If I come across a number in lst2, at a certain index, that the same as lst1 I want
            #to execute the following:
            if l2[indexNum] == num:

                #I've added a blank list at the top, newLst, which I want to append the matching number to.
                newLst.append(l2[indexNum])

                #I'll also want to still add one to the indexNum variable to compare the next number in lst2
                indexNum = indexNum + 1

                break

                #If the number at lst2[indexNum] isn't equal to that of lst1, I still want to add to the
                ##indexNum variable to keep going through the loop and comparing the other items.
            else:
                indexNum = indexNum + 1

        ## I'm thinking here that if at the end of the outer loop, if my newLst is equal to the lst1, then that
        ## should mean that it works as a sub list. I could be wrong here and my thinking is way off though.
        ## If it is equal then the return value should be true, if not false.
        if l1 == newLst:
            return True
        else:
            return False
    return True
Теги:
list
python-3.x

2 ответа

2
Лучший ответ

Я пошел и проверил ваш код. Должен сказать, похоже, что кто-то намеренно ввел плохие строки в совершенно приятное решение:

  1. У вас есть рекурсивный вызов в 6-й строке функции. Это не только бесполезно, но и заставит функцию продолжать рекурсию.
  2. Это окончательное, if...else также убивает его. Очевидно, newlst не будет равняться l1, так как к тому времени, как вы сюда попадете, вы проверили только один элемент в большей части l1 - Удалите его.
  3. Который делает newlst бесполезным.
  4. Великое использование другого на время. Не вижу много пользы от этого так же естественно, как здесь - хорошо!

Дополнения от @Olivier, которые я пропустил

  1. Проверка l1 пуста избыточна - цикл будет пропущен, и вы вернетесь True
  2. Перед разрывом вам все равно необходимо увеличить счетчик

Это фиксированное решение:

def subList(l1, l2):
    indexNum = 0
    if len(l1) > len(l2): return False

    for num in l1:
        while indexNum < len(l2):
            if l2[indexNum] == num: 
                indexNum = indexNum + 1
                break
            indexNum = indexNum + 1
        else:
            return False
    return True

l1 = [15,1,100]
l2 = [20,15,30,50,1,100]
l3 = [15,50,20]
print(subList(l1,l2))
print(subList(l3,l2))

Логика вашего цикла:

  1. Возьмите элемент из l1.
  2. Петля, пока вы не найдете ее в l2. indexNum управляет этой indexNum между итерациями.
  3. else если вы его не нашли, верните False.
  4. Верните True если вам удалось сделать это для всех элементов в l1.

Ваше решение не простое, но и самое эффективное.

  • 0
    Ух ты. Большое спасибо за вашу помощь, особенно за полный разрыв цикла. Это действительно облегчило понимание.
  • 0
    На самом деле вы должны убедиться, что indexNum увеличивается, прежде чем прерывать цикл while. Если вы протестируете с первым списком [15, 1, 1, 100] например, с l2, ваш код вернет True неправильно. Также if l1 == []: return True в вашем коде и код @Coop не требуется, пустой список означает нулевую итерацию цикла for, и вы все равно возвращаете True.
Показать ещё 2 комментария
0

Вы можете решить эту проблему, используя понимание списка и встроенную функцию all(), чтобы проверить, равны ли списки


l1 = [1,3,4]

l2 = [7,9,1,2,1,3,4,9,8,1,3,4,9]

# the length of the looked for list
lenL1=len(l1)

# create all sublists of this length from each starting position of l2 up to its end
# and check if this sublist has exactly the same digits as the l1 list using all()
a = [(l2[i:i+lenL1],i) for i in range(len(l2)-lenL1) \
                       if all(l1[q]==l2[i+q] for q in range(lenL1))]

print(a)

Выход:

[([1, 3, 4], 4), ([1, 3, 4], 9)]

Он нашел подсписку в столбцах 4 и 9 в l2


Если вы предпочитаете "выписывать" метод вместо понимания списка, вы можете сделать что-то подобное:

def checker(l1,l2):
    """Enuimerates over l2, finds a value thats same as l1[0] and delegates
    sublistchecking to inner function checkSame"""
    def checkSame(a,b):
        """gets two lists of same length and checks that theire values are identical"""
        return all(a[i] == b[i] for i in range(1,len(a))) # 0 was checked already

    l1_len = len(l1) # store length so we do not need to lookup it all the time

    for idx,value in enumerate(l2):
        if value == l1[0]:          # check 0
            if  checkSame(l1,l2[idx:idx+l1_len]):
                yield(l1,idx) 

print(list(checker(l1,l2)))

Я предпочитаю использовать enumerate(iterable) если мне нужен индекс во что-то итеративное вместе с значением - перечисление возвращает оба:

Перечисление Doku (iterable [, start])

Ещё вопросы

Сообщество Overcoder
Наверх
Меню