#python #string #list #python-3.8
Вопрос:
У меня есть список строк. Я хочу создать вложенные списки из списка таким образом, чтобы он содержал строки из исходного списка, но так, чтобы количество слов в каждом вложенном списке было меньше 16, а предыдущая строка должна быть первым элементом вложенного списка, за исключением первого подсписка.
Чтобы привести пример, предположим, что мой список приведен ниже и содержит 5 строк, каждая из которых содержит различное количество слов.
qq = ['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar', 'students difficulties in grammar', 'difficulties of english grammar']
Я хочу создать вложенные списки, удовлетворяющие вышеуказанному условию, максимум с 16 словами, и каждый список содержит предыдущую строку в качестве первого элемента (кроме первого вложенного списка). Там будет только два подсписка, и мой вывод будет
q1 = ['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar']
q2 = ['difficulties of grammar', 'students difficulties in grammar', 'difficulties of english grammar']
Это то, что я пробовал. Правильно ли это и есть ли лучший способ сделать это ? У меня есть миллионы списков для выполнения этой операции.
qq = ['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar', 'students difficulties in grammar', 'difficulties of english grammar']
psz = 0
pi = 0
msz = 16
subqq = list()
qq_i = list()
for i in range(len(qq)):
csz=psz len(qq[i].split())
if (csz>msz):
subqq.append(qq_i.copy())
qq_i.clear()
qq_i.append(qq[i-1])
qq_i.append(qq[i])
psz = 0
else:
qq_i.append(qq[i])
psz = len(qq[i].split())
subqq.append(qq_i)
Комментарии:
1. Что вы пробовали до сих пор?
2. @Phydeaux Я тоже добавил свой код.
Ответ №1:
Вот что я придумал. Это алгоритм, аналогичный вашему и ответу Соруша Бахтиария, но он не должен содержать ошибок в подсчете слов, и я думаю, что его легче читать.
Это также приводит к ошибке в случае, когда мы начинаем новый подсписок с последней фразы в предыдущем и не можем добавить следующую фразу, не нарушив ограничение на количество слов. Это может произойти, если есть две последовательные фразы, в которых >8 слов — если вы можете быть уверены, что этого никогда не произойдет, вы можете опустить эту часть.
def count_words(phrase):
return len(phrase.split())
def sublists_with_max_words(main_list, max_words=16):
output_sublists = []
current_sublist = []
current_sublist_words = 0
for phrase in main_list:
words_in_phrase = count_words(phrase)
if (current_sublist_words words_in_phrase) > max_words:
# If we cannot add the phrase to the sublist without breaking
# the word limit, then add the sublist to the output
output_sublists.append(current_sublist)
# Start a new sublist with the last phrase we added
last_phrase = current_sublist[-1]
current_sublist = [last_phrase]
current_sublist_words = count_words(last_phrase)
# If we cannot add the phrase to the new sublist either, then raise
# an exception as we cannot continue without breaking the word limit
if (current_sublist_words words_in_phrase) > max_words:
raise ValueError(
f"Cannot add '{phrase}' ({words_in_phrase} words) to a new"
f" sublist with {current_sublist_words} words"
)
# Add the current phrase to the sublist
current_sublist.append(phrase)
current_sublist_words = words_in_phrase
# At the end of the loop, add the working sublist to the output
output_sublists.append(current_sublist)
return output_sublists
print(sublists_with_max_words(qq))
Ответ №2:
Мой похож на ваш, и алгоритм в основном тот же, но я считаю, что это должно работать немного быстрее:
def fn(lst, n):
word_count = 0
res = []
temp_lst = []
for item in lst:
len_current_item = len(item.split())
word_count = len_current_item
if word_count < n:
temp_lst.append(item)
else:
res.append(temp_lst)
last_item = res[-1][-1]
temp_lst = [last_item, item]
word_count = len_current_item len(last_item.split())
res.append(temp_lst)
# Checking for last item's lenght as Phydeaux pointed out in comments.
if word_count > n:
res.append([temp_lst.pop()])
return res
выход :
['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar']
['difficulties of grammar', 'students difficulties in grammar', 'difficulties of english grammar']
Я старался избегать копирования и очистки, а также немного небольших изменений.
Комментарии:
1. Это похоже на то, что я придумал, но, к вашему сведению
word_count = len(item.split())
, не учитывает слова вres[-1][-1]
2. Также стоит учитывать, что происходит, когда есть два последовательных элемента, в которых >8 слов — в этом случае невозможно включить предыдущий элемент в новый список и не нарушить ограничение на количество слов. Не уверен, что ОП хочет, чтобы это произошло в этом случае
3. @Phydeaux Не могли бы вы подробнее рассказать о своем первом комментарии ? Вы указываете на последнюю итерацию, которая
res[-1][-1]
не учитывается?4. Вы задаете количество слов только для текущего элемента, но в подсписке есть два элемента
5. @Phydeaux Спасибо, ты прав, это уже должно быть исправлено.
Ответ №3:
Поскольку другие уже предоставили действительные решения, вот еще один интересный подход, реализованный с помощью схемы сопоставления между каждым qq
элементом и соответствующим совокупным количеством слов.
Во-первых, создайте диктат сопоставления:
qq_map = {q: len(" ".join(qq[:n 1]).split()) for n, q in enumerate(qq)}
# {'blended e learning forumin planning': 5, 'difficulties of learning as forigen language': 11,
# 'difficulties of grammar': 14, 'students difficulties in grammar': 18,
# 'difficulties of english grammar': 22}
Затем вы создаете сгруппированный список с информацией о сопоставлении:
qq = [[q for q in qq if qq_map[q] in range(i*16, (i 1)*16)] /
for i in range(-(-qq_map[qq[-1]] // 16))]
# [['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar'],
# ['students difficulties in grammar', 'difficulties of english grammar']]
Примечание:
-(-qq_map[qq[-1]] // 16)
является эквивалентомmath.ceil(qq[-1] / 16)
. Вы можете
заменить его, если хотите получить более краткое и менее «арифметическое»
выражение.
Наконец, вы снова обрабатываете список, чтобы вставить последнюю строку каждой группы в следующую (кроме самой первой, конечно).:
qq = [[qq[i-1][-1]] qq[i] if i != 0 else qq[i] for i in range(len(qq))]
# [['blended e learning forumin planning', 'difficulties of learning as forigen language', 'difficulties of grammar'],
# ['difficulties of grammar', 'students difficulties in grammar', 'difficulties of english grammar']]