Поэтому код, над которым я работаю, предназначен для бота IRC, и я хочу реализовать способ ограничения каналов на основе CHANLIMIT
сервера CHANLIMIT
.
Опция CHANLIMIT
представляет собой список ограничений с префиксом и пределом, CHANLIMIT
:
но если после :
ничего нет, то ограничения нет.
Решение ниже работает, но я ищу какие-либо улучшения в нем.
result = ['#+:2', '&:']
channels = ['#test1', '#test2', '+test3', '&test4']
prefix_groups = [(prefix, []) for prefix in result]
channel_groups = {k: v for (k, v) in prefix_groups}
for channel in channels:
for group in prefix_groups:
if channel[0] in group[0]:
channel_groups[group[0]].append(channel)
break
for prefix, channels in channel_groups.items():
limit = prefix.split(':')[1]
if limit:
if len(channels) > int(limit):
channel_groups[prefix] = channels[:int(limit)]
channels = [
channel for chanlist in channel_groups.values() for channel in chanlist]
print(channels)
Но давай бекап немного. Если я правильно понимаю, в конце вы хотите список элементов channels_to_test
который соответствует префиксам и не превышает лимит префикса, если таковой имеется. Вы можете реализовать это поведение фильтрации в генераторе:
Решение 4
import re
results = ['#+:2', '&:']
channels_to_test = ['#test1', '#test2', '+test3', '&test4',
'#test5', '!test5', '&test6', '&test7',
'+test8', '#test9']
def filter_channel_list(prefixes_to_match, input_channel_list):
prefix_pattern = re.compile(r'^(.*):(\d+)?$')
prefix_matches = (prefix_pattern.match(x) for x in prefixes_to_match)
prefix_split = (x.groups() for x in prefix_matches)
prefixes_remaining = {x: (int(y) if y is not None else None)
for (x, y) in prefix_split}
for current_channel in input_channel_list:
for (prefix, nb_left) in prefixes_remaining.items():
if current_channel[0] in prefix:
if nb_left is None:
yield current_channel
break
else:
if nb_left > 0:
prefixes_remaining[prefix] -= 1
yield current_channel
break
else:
continue
result_channels = list(filter_channel_list(results, channels_to_test))
print(result_channels)
Вот несколько комментариев:
channels_to_test
соответствовал только одному элементу results
. Это из-за операторов break
размещенных в генераторе.results
и уменьшение значения каждый раз, когда мы сталкиваемся с совпадением с элементом channels_to_test
. Если это значение станет 0, генератор перейдет к следующему значению. Это то, что делает (необязательно в данном случае) оператор continue
.for
от того, что вы делаете с ними. В вашем конкретном случае одним из преимуществ может быть то, что вы итерируете только один раз для channels_to_test
вместо того, чтобы создавать словарь, содержащий списки, которые вы должны в конечном итоге выровнять, чтобы извлечь свой ответ, но что более важно, вы выбираете решение, которое сможете чтобы понять через шесть месяцев, когда вы вернетесь к этому коду
Когда мне нужно извлечь некоторую информацию из строк, я склонен использовать регулярные выражения. Таким образом, расширяя Решение 2, мы можем получить:
Решение 3
import re
import itertools
results = ['#+:2', '&:']
channels_to_test = ['#test1', '#test2', '+test3', '&test4',
'#test5', '!test5', '&test6', '&test7',
'+test8', '#test9']
prefix_pattern = re.compile(r'^(.*):(\d+)?$')
prefix_matches = (prefix_pattern.match(x) for x in results)
prefix_split = (x.groups() for x in prefix_matches)
channel_groups = {group: [channel for channel in channels_to_test
if channel[0] in group[0]]
for group in prefix_split}
prefix_existing_limit = ((x, int(x[1])) for x in channel_groups
if x[1] is not None)
modified_channel_groups = {prefix_group: channel_groups[prefix_group][:limit]
for (prefix_group, limit) in prefix_existing_limit}
channel_groups.update(modified_channel_groups)
result_channels = list(itertools.chain.from_iterable(channel_groups.values()))
print(result_channels)
:
чтобы получить вашу информацию. Но если у вас есть более точные требования для извлечения ваших групп, регулярные выражения могут оказаться полезными (например, в случае, если ваши результаты описаны по-другому). Регулярные выражения значительно упрощают поиск шаблонов в тексте. Но это зависит от вас, чтобы делать то, что вам подходит.
Есть много способов решить эту проблему. Делая некоторые минимальные упрощения, вы можете получить что-то вроде этого:
Решение 1
results = ['#+:2', '&:']
channels_to_test = ['#test1', '#test2', '+test3', '&test4',
'#test5', '!test5', '&test6', '&test7',
'+test8', '#test9']
channel_groups = {k: [] for k in results}
for channel in channels_to_test:
for group in results:
if channel[0] in group:
channel_groups[group].append(channel)
break
for prefix, channels in channel_groups.items():
limit = prefix.split(':')[1]
if limit:
limit = int(limit)
channel_groups[prefix] = channels[:limit]
result_channels = [
channel for chanlist in channel_groups.values() for channel in chanlist]
print(result_channels)
Вот изменения, которые я сделал:
channel_groups
напрямую, вместо того, чтобы создавать список кортежей (prefix_groups
), а затем использовал его для создания channel_groups
group
по results
вместо того, чтобы prefix_groups
len(channels) > int(limit)
потому что даже если длина channels
меньше или равна limit
, channels[:limit]
вернет все channels
Мы можем пойти дальше:
Решение 2
import itertools
results = ['#+:2', '&:']
channels_to_test = ['#test1', '#test2', '+test3', '&test4',
'#test5', '!test5', '&test6', '&test7',
'+test8', '#test9']
channel_groups = {group: [channel for channel in channels_to_test
if channel[0] in group]
for group in results}
limit = lambda prefix: prefix.split(':')[1]
modified_channel_groups = {prefix: channels[:int(limit(prefix))]
for (prefix, channels) in channel_groups.items()
if limit(prefix)}
channel_groups.update(modified_channel_groups)
result_channels = list(itertools.chain.from_iterable(channel_groups.values()))
print(result_channels)
Но здесь я должен сделать предположение: я предположил, что канал может соответствовать максимум одному элементу results
. Другими словами, никакие два элемента results
будут соответствовать одному каналу. Скажите, если это не так для вашей ситуации.
Вот изменения, которые я сделал:
channel_groups
используя словарное понимание, где каждое значение элемента - это понимание списка.modified_channel_groups
который содержит элементы channel_groups
, которые были сокращеныchannel_groups
с теми же, что и modified_channel_groups
modified_channel_groups
выражения, чтобы я мог включить его в modified_channel_groups
определения.result_channels
используя itertools.chain.from_iterable()
Вы можете даже дальше, так что вы создаете свой ответ channel_groups
напрямую, но его становится труднее читать. Поэтому я не рекомендую это:
Решение 2а
import itertools
results = ['#+:2', '&:']
channels_to_test = ['#test1', '#test2', '+test3', '&test4',
'#test5', '!test5', '&test6', '&test7',
'+test8', '#test9']
limit = lambda prefix: prefix.split(':')[1]
channel_groups = {group: [channel for channel in channels_to_test if channel[0] in group][:int(limit(group)) if limit(group) else None]
for group in results}
result_channels = list(itertools.chain.from_iterable(channel_groups.values()))
print(result_channels)
Просто несколько вещей, чтобы отметить:
channel_groups
создается так же, как в решении 2, но каждое значение словаря является списком (полученным из понимания), который разделен на целочисленное значение текущей group
или None
что будет означать принятие всех значений.