Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 16, 2018 11:53:53

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

Привет всем!
Писал сравнение списков, где важен порядок элементов. Написал:

 #!/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
Собственно, вопрос: а почему так нельзя? Логично было бы же.

Офлайн

#2 Ноя. 16, 2018 12:38:07

Slow
Зарегистрирован: 2017-07-26
Сообщения: 88
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

Наверное потому, что и in, и index ищут элементы, а не последовательности оных.
Другими словами, не логично было бы использовать операторы/функции, от которых все, кроме, возможно, вас, ожидают поиска элемента для поиска последовательностей.

PS. Кстати,

x in some_list
на самом деле работает как
some_list.__contains__(x)
Что как бы намекает нам на возможность при желании переопределить поведение in, но делать так всё-же не стоит.

Офлайн

#3 Ноя. 16, 2018 12:50:19

rami
Зарегистрирован: 2018-01-08
Сообщения: 281
Репутация: +  72  -
Профиль   Отправить e-mail  

lst1 in lst2

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)

Офлайн

#4 Ноя. 16, 2018 13:12:27

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

rami, Slow

Если в lst1 добавить как элемент lst2, то сразу найдёт
Ясно, спасибо!

Офлайн

#5 Ноя. 16, 2018 13:30:08

Rafik
Зарегистрирован: 2018-09-04
Сообщения: 231
Репутация: +  27  -
Профиль   Отправить e-mail  

lst1 in lst2

Если надо получить ответ “Да” или “Нет” и список содержит только строки (str), то можно преобразовать списки в строки и сравнить их.

 rez = False
a = ",".join(lst1)
b = ",".join(lst2)
if b in a:
    rez = True 
Если требуется индекс в списке1, тогда вычисляем через количество запятых в срезе от начала до места сопадения.

Офлайн

#6 Ноя. 16, 2018 14:19:31

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

Rafik
так нельзя:

 >>> lst1 = ['список','содержащий']
>>> lst2 = ['список','с']
>>> a = ",".join(lst1)
>>> b = ",".join(lst2)
>>> b in a
True

Офлайн

#7 Ноя. 16, 2018 16:17:47

Slow
Зарегистрирован: 2017-07-26
Сообщения: 88
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

например, так:

 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

Отредактировано Slow (Ноя. 16, 2018 17:06:37)

Офлайн

#8 Ноя. 16, 2018 18:49:50

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

Slow
Спасибо. В итоге выяснилось, что работа со списками слишком медленная для длинных текстов, поэтому я действительно лучше сначала преобразую список в строку, как советовал Rafik, только добавлю по бокам пробелов, чтобы исключить ненужные совпадения.

Отредактировано vanvanov (Ноя. 16, 2018 18:50:17)

Офлайн

#9 Ноя. 17, 2018 01:19:42

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10024
Репутация: +  857  -
Профиль   Отправить e-mail  

lst1 in lst2

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
>>>



Отредактировано py.user.next (Ноя. 17, 2018 01:21:29)

Офлайн

#10 Ноя. 17, 2018 09:18:52

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

lst1 in lst2

py.user.next
Согласен, алгоритм со строками неполноценен. Но у меня для него специфическое применение - только в тексте и без дублирующихся пробелов. Я уже пробовал (и вчера, и год назад) алгоритмы со списками, но везде это слишком долго - 5 мин на 2 текстах суммарно в 22 страницы. Разумеется, везде подряд хак со строками я применять не буду. Возможно, стоит приглядеться к массивам numpy, я не знаю.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version