Найти все возможные подписи списка
Скажем, у меня есть следующий список
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
Я хочу найти все возможные подсписчики определенной длины, где они не содержат одного определенного номера и не теряют порядок чисел.
Например, все возможные подписи с длиной 6 без 12:
[1,2,3,4,5,6]
[2,3,4,5,6,7]
[3,4,5,6,7,8]
[4,5,6,7,8,9]
[5,6,7,8,9,10]
[6,7,8,9,10,11]
[13,14,15,16,17,18]
Проблема в том, что я хочу сделать это в очень большом списке, и мне нужен самый быстрый способ.
Обновить с помощью моего метода:
oldlist = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
newlist = []
length = 6
exclude = 12
for i in oldlist:
if length+i>len(oldlist):
break
else:
mylist.append(oldlist[i:(i+length)]
for i in newlist:
if exclude in i:
newlist.remove(i)
Я знаю, что это не лучший метод, поэтому мне нужен лучший.
Ответы
Ответ 1
Простое, не оптимизированное решение было бы
result = [sublist for sublist in
(lst[x:x+size] for x in range(len(lst) - size + 1))
if item not in sublist
]
Оптимизированная версия:
result = []
start = 0
while start < len(lst):
try:
end = lst.index(item, start + 1)
except ValueError:
end = len(lst)
result.extend(lst[x+start:x+start+size] for x in range(end - start - size + 1))
start = end + 1
Ответ 2
Используйте itertools.combinations
:
import itertools
mylist = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
def contains_sublist(lst, sublst):
n = len(sublst)
return any((sublst == lst[i:i+n]) for i in xrange(len(lst)-n+1))
print [i for i in itertools.combinations(mylist,6) if 12 not in i and contains_sublist(mylist, list(i))]
Печать
[(1, 2, 3, 4, 5, 6), (2, 3, 4, 5, 6, 7), (3, 4, 5, 6, 7, 8), (4, 5, 6, 7, 8, 9), (5, 6, 7, 8, 9, 10), (6, 7, 8, 9, 10, 11), (13, 14, 15, 16, 17, 18)]
Ответ 3
Самый простой способ, который я могу представить, - удалить исключенный номер из списка, а затем использовать itertools.combinations()
для генерации желаемых подписок, это имеет дополнительное преимущество, что оно будет производить подсписки итеративно.
from itertools import combinations
def combos_with_exclusion(lst, exclude, length):
for combo in combinations((e for e in lst if e != exclude), length):
yield list(combo)
mylist = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
for sublist in combos_with_exclusion(mylist, 12, 6):
print sublist
Вывод:
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 7]
[1, 2, 3, 4, 5, 8]
[1, 2, 3, 4, 5, 9]
[1, 2, 3, 4, 5, 10]
[1, 2, 3, 4, 5, 11]
[1, 2, 3, 4, 5, 13]
...
[11, 14, 15, 16, 17, 18]
[13, 14, 15, 16, 17, 18]
Ответ 4
Мне нравится создавать решения из небольших составных частей. Несколько лет написания Haskell делает это с вами. Поэтому я бы сделал это так...
Во-первых, это вернет итератор по всем подспискам в порядке возрастания длины, начиная с пустого списка:
from itertools import chain, combinations
def all_sublists(l):
return chain(*(combinations(l, i) for i in range(len(l) + 1)))
В целом нам не рекомендуется использовать однобуквенные имена переменных, но я думаю, что в коротких очередях с очень абстрактным кодом это вполне разумная вещь.
(BTW, чтобы опустить пустой список, используйте range(1, len(l) + 1)
).
Затем мы можем решить вашу проблему в целом, добавив ваши критерии:
def filtered_sublists(input_list, length, exclude):
return (
l for l in all_sublists(input_list)
if len(l) == length and exclude not in l
)
Итак, например:
oldlist = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
length = 6
exclude = 12
newlist = filtered_sublists(old_list, length, exclude)
Ответ 5
Моя попытка рекурсивного создания всех возможных списков. Параметр depth просто берет количество элементов для удаления из каждого списка. Это не скользящее окно.
код:
def sublists(input, depth):
output= []
if depth > 0:
for i in range(0, len(input)):
sub= input[0:i] + input[i+1:]
output += [sub]
output.extend(sublists(sub, depth-1))
return output
Примеры (введенные интерактивно в python3):
sublists([1,2,3,4],1)
[[2, 3, 4], [1, 3, 4], [1, 2, 4], [1, 2, 3]]
sublists([1,2,3,4],2)
[[2, 3, 4], [3, 4], [2, 4], [2, 3], [1, 3, 4], [3, 4], [1, 4] [1, 3], [1, 2, 4], [2, 4], [1, 4], [1, 2], [1, 2, 3], [2, 3], [1, 3 ], [1, 2]]
sublists([1,2,3,4],3)
[[2, 3, 4], [3, 4], [4], [3], [2, 4], [4], [2], [2, 3], [3] [2], [1, 3, 4], [3, 4], [4], [3], [1, 4], [4], [1], [1, 3], [3] [1], [1, 2, 4], [2, 4], [4], [2], [1, 4], [4], [1], [1, 2], [2] 1, 2, 3, 3, 3, [1]]
Некоторые краевые случаи:
sublists([1,2,3,4],100)
[[2, 3, 4], [3, 4], [4], [3], [2, 4], [4], [2], [2, 3], [3] [2], [1, 3, 4], [3, 4], [4], [3], [1, 4], [4], [1], [1, 3], [3] [1], [1, 2, 4], [2, 4], [4], [2], [1, 4], [4], [1], [1, 2], [2] 1, 2, 3, 3, 3, [1]]
sublists([], 1)
[]
ПРИМЕЧАНИЕ: список результатов списка включает дубликаты.
Ответ 6
У меня есть ответ, но я думаю, что это не самое лучшее:
oldlist = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
result = []
def sub_list(lst):
if len(lst) <= 1:
result.append(tuple(lst))
return
else:
result.append(tuple(lst))
for i in lst:
new_lst = lst[:]
new_lst.remove(i)
sub_list(new_lst)
sub_list(oldlist)
newlist = set(result) # because it have very very very many the same
# sublist so we need use set to remove these also
# use tuple above is also the reason
print newlist
Он получит результат, но приведет к тому, что у него будет такой же подсписк, чтобы он нуждался в большой памяти и много времени. Я думаю, что это не очень хорошо.