Я хорошо осведомлен о следующем вопросе, который также существует при переполнении стека. Строка Неизвестный шаблон. Соответствие, но ответ там не работает для меня.
Моя проблема следующая. Я получаю строку символов, например
- "1211", и мне нужно сделать, чтобы увидеть, что 1 чаще всего повторяется, и это 2 раза подряд.
- Но это также может быть "121212112", где 12 повторяется 3 раза подряд.
- Но с 12221221 221 повторяется 2 раза, а не 2, что повторяется 3 раза.
вот некоторые результаты, которые мне нравятся (единственные числа, которые когда-либо использовались, - 1 и 2)
>>> counter('1211')
1
>>> counter('1212')
2
>>> counter('21212')
2
результат я хочу, сколько раз это происходит.
Я понятия не имею, как начать поиск шаблона, поскольку он не известен на forehand, и я провел некоторое исследование в Интернете и не нашел ничего подобного.
Кто-нибудь знает, как я даже начинаю решать эту проблему? Вся помощь приветствуется, и если вы хотите получить дополнительную информацию, не стесняйтесь, дайте мне знать.
Действительно неэффективен, но вы можете
Очевидно, вы можете использовать некоторую datastructure для прохождения через строку один раз и делать некоторые подсчеты на пути, но поскольку я не уверен, что ваши ограничения и желаемый результат, я могу дать вам только это.
Я согласен с Jirka, не уверен, как вы набираете длинный и короткий, чтобы выбрать оптимальные результаты, но эта функция даст вам меню:
#Func1
def sub_string_cts(string):
combos = {}
for i in range(len(string)):
u_start = len(string) - i
for start in range(u_start):
c_str = string[start:i+start+1]
if c_str in combos:
combos[c_str] += 1
else:
combos[c_str] = 1
return combos
sub_string_cts('21212')
{'2': 3,
'1': 2,
'21': 2,
'12': 2,
'212': 2,
'121': 1,
'2121': 1,
'1212': 1,
'21212': 1}
После вашего комментария я думаю, что это больше того, что вы ищете:
#Func2
def sub_string_cts(string):
combos = {}
for i in range(len(string)):
u_start = len(string) - i
substrs = set([string[start:i+start+1] for start in range(u_start)])
for substring in substrs:
combos[substring] = max([len(i) for i in re.findall("((?:{})+)".format(substring), string)])//len(substring)
return combos
sub_string_cts('21212')
{'2': 1,
'1': 1,
'21': 2,
'12': 2,
'212': 1,
'121': 1,
'2121': 1,
'1212': 1,
'21212': 1}
Вы можете сузить это до "лучших" кандидатов, свернув на самый верхний экземпляр каждой длины строки:
def max_by_len(result_dict):
results = {}
for k, v in result_dict.items():
if len(k) not in results:
results[len(k)] = {}
for c_len in [ln for ln in results]:
len_max_count = max([v for (k, v) in result_dict.items() if len(k) == c_len])
for k,v in result_dict.items():
if len(k) == c_len:
if v == len_max_count:
results[c_len][k] = v
return results
#Func1:
max_by_len(sub_string_cts('21212'))
{1: {'2': 3},
2: {'21': 2, '12': 2},
3: {'212': 2},
4: {'2121': 1, '1212': 1},
5: {'21212': 1}}
#Func2:
max_by_len(sub_string_cts('21212'))
{1: {'2': 1, '1': 1},
2: {'21': 2, '12': 2},
3: {'212': 1, '121': 1},
4: {'2121': 1, '1212': 1},
5: {'21212': 1}}
Предполагая, что мы не будем выбирать "2121" или "1212", потому что их появление соответствует "21212", и они короче по длине, и аналогичным образом мы не будем выбирать "21" или "12", поскольку они происходят с одинаковой частотой поскольку "212" мы могли бы ограничить наших жизнеспособных кандидатов до "2", "212" и "21212" следующим кодом:
def remove_lesser_patterns(result_dict):
len_lst = sorted([k for k in result_dict], reverse=True)
#len_lst = sorted([k for k in max_len_results])
len_crosswalk = {i_len: max([v for (k,v) in result_dict[i_len].items()]) for i_len in len_lst}
for i_len in len_lst[:-1]:
eval_lst = [i for i in len_lst if i < i_len]
for i in eval_lst:
if len_crosswalk[i] <= len_crosswalk[i_len]:
if i in result_dict:
del result_dict[i]
return result_dict
#Func1
remove_lesser_patterns(max_by_len(sub_string_cts('21212')))
{1: {'2': 3}, 3: {'212': 2}, 5: {'21212': 1}}
#Func2
remove_lesser_patterns(max_by_len(sub_string_cts('21212')))
{2: {'21': 2, '12': 2}, 5: {'21212': 1}}
Результаты:
test_string = ["1211", "1212", "21212", "12221221"]
for string in test_string:
print("<Input: '{}'".format(string))
c_answer = remove_lesser_patterns(max_by_len(sub_string_cts(string)))
print("<Output: {}\n".format(c_answer))
<Input: '1211'
<Output: {1: {'1': 2}, 4: {'1211': 1}}
# '1' is repeated twice
<Input: '1212'
<Output: {2: {'12': 2}, 4: {'1212': 1}}
# '12' is repeated twice
<Input: '21212'
<Output: {2: {'21': 2, '12': 2}, 5: {'21212': 1}}
# '21' and '12' are both repeated twice
<Input: '12221221'
<Output: {1: {'2': 3}, 3: {'221': 2}, 8: {'12221221': 1}}
# '2' is repeated 3 times, '221' is repeated twice
Эти функции вместе дают вам наивысшее появление каждого шаблона по длине. Ключом к словарю является длина, с под-словарем самых высоких (несколько, если привязаны) существующих шаблонов.
Func2 требует, чтобы паттерны были последовательными, тогда как Func1 не является - он строго основан на возникновении.
С вашим примером:
3. But with 12221221 it is 221 that is repeated 2 times rather than 2 that repeats 3 times.
код решает эту двусмысленность в желаемом выходе (2 или 3), предоставляя вам оба:
<Input: '12221221'
<Output: {1: {'2': 3}, 3: {'221': 2}, 8: {'12221221': 1}}
# '2' is repeated 3 times, '221' is repeated twice
Если вас интересуют только две длины символов, вы можете легко вывести их из результатов max_by_len
следующим образом:
test_string = ["1211", "1212", "21212", "12221221"]
for string in test_string:
print("<Input: '{}'".format(string))
c_answer = remove_lesser_patterns({k:v for (k,v) in max_by_len(sub_string_cts(string)).items() if k == 2})
print("<Output: {}\n".format(max([v for (k,v) in c_answer[2].items()])))
#Func2
<Input: '1211'
<Output: 1
<Input: '1212'
<Output: 2
<Input: '21212'
<Output: 2
<Input: '12221221'
<Output: 1