Найти - Пользователи
Полная версия: lst1 in lst2
Начало » Python для новичков » lst1 in lst2
1 2
vanvanov
Привет всем!
Писал сравнение списков, где важен порядок элементов. Написал:
 #!/usr/bin/python3
# -*- coding: UTF-8 -*-
import difflib
class List:
    def __init__(self,lst1=[],lst2=[]):
        if lst1 is None:
            self.lst1 = []
        else:
            self.lst1 = list(lst1)
        if lst2 is None:
            self.lst2 = []
        else:
            self.lst2 = list(lst2)
    # Find shared elements (strict order), based on 'self.diff'
    def shared_strict(self):
        seqm = difflib.SequenceMatcher(a=self.lst1,b=self.lst2)
        output = []
        for opcode, a0, a1, b0, b1 in seqm.get_opcodes():
            if opcode == 'equal':
                output += seqm.a[a0:a1]
        return output
    
    # Check if 'lst1' fully comprises 'lst2' (strict order)
    def eats_strict(self):
        if self.lst2 == self.shared_strict():
            return True
if __name__ == '__main__':
    lst1 = ['черная','и','белая','кошка']
    lst2 = ['белая','кошка']
    print(List(lst1,lst2).eats_strict())
Потом думаю: чего это я фигнёй маюсь, наверное, ‘in’ или ‘index’ сработают. Но нет:
 >>> lst1 = ['a','b','c','d','e','f','g']
>>> lst2 = ['e','f','g']
>>> lst1.index(lst2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: ['e', 'f', 'g'] is not in list
>>> lst2 in lst1
False
Собственно, вопрос: а почему так нельзя? Логично было бы же.
Slow
Наверное потому, что и in, и index ищут элементы, а не последовательности оных.
Другими словами, не логично было бы использовать операторы/функции, от которых все, кроме, возможно, вас, ожидают поиска элемента для поиска последовательностей.

PS. Кстати,
x in some_list
на самом деле работает как
some_list.__contains__(x)
Что как бы намекает нам на возможность при желании переопределить поведение in, но делать так всё-же не стоит.
rami
in, и index ищут то, что им говорят, вы говорите найти список lst2 в списке lst1, а в нём нет никаких списков, только строковые элементы. Если в lst1 добавить как элемент lst2, то сразу найдёт:
 lst2 = ['e','f','g']
lst1 = ['a','b','c',lst2,'d','e','f','g']
print(lst1.index(lst2))
print(lst2 in lst1)
vanvanov
rami, Slow
Если в lst1 добавить как элемент lst2, то сразу найдёт
Ясно, спасибо!
Rafik
Если надо получить ответ “Да” или “Нет” и список содержит только строки (str), то можно преобразовать списки в строки и сравнить их.
 rez = False
a = ",".join(lst1)
b = ",".join(lst2)
if b in a:
    rez = True 
Если требуется индекс в списке1, тогда вычисляем через количество запятых в срезе от начала до места сопадения.
vanvanov
Rafik
так нельзя:
 >>> lst1 = ['список','содержащий']
>>> lst2 = ['список','с']
>>> a = ",".join(lst1)
>>> b = ",".join(lst2)
>>> b in a
True
Slow
например, так:
 def index_of_subsequence(container, subsequence):
    if len(subsequence) > len(container):
        return None
    for i in range(len(container) - len(subsequence) + 1):
        for c_, s_ in zip(container[i:], subsequence):
            if c_ != s_:
                break
        else:
            return i
вернет либо индекс первого вхождения, либо None
vanvanov
Slow
Спасибо. В итоге выяснилось, что работа со списками слишком медленная для длинных текстов, поэтому я действительно лучше сначала преобразую список в строку, как советовал Rafik, только добавлю по бокам пробелов, чтобы исключить ненужные совпадения.
py.user.next
vanvanov
поэтому я действительно лучше сначала преобразую список в строку
Не надо список преобразовывать в строку, это может приводить к редким ошибкам, которые не видны изначально. К тому же список может содержать не только строки, но и элементы произвольных типов, с которыми ты не сможешь сделать .join().

Вот пример, как предложенный выше код выдаёт ложный результат
  
>>> lst1 = ['a', ',', 'b', 'c', 'd']
>>> lst2 = [',,b', 'c']
>>> 
>>> rez = False
>>> a = ",".join(lst1)
>>> b = ",".join(lst2)
>>> 
>>> if b in a:
...     rez = True
... 
>>> rez
True
>>>
vanvanov
py.user.next
Согласен, алгоритм со строками неполноценен. Но у меня для него специфическое применение - только в тексте и без дублирующихся пробелов. Я уже пробовал (и вчера, и год назад) алгоритмы со списками, но везде это слишком долго - 5 мин на 2 текстах суммарно в 22 страницы. Разумеется, везде подряд хак со строками я применять не буду. Возможно, стоит приглядеться к массивам numpy, я не знаю.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB