Использование reduce () для получения частоты каждой пары / тройки символов в строке? - PullRequest
0 голосов
/ 07 мая 2020

Я должен выполнить эту задачу функционально, поэтому никаких циклов.

Я уже выполнил задачу по поиску частоты одиночных символов. Мой код выглядит так:

char_freq = {}

    def getcharfreq(char_freq, ch):
        char_freq[ch] = char_freq.get(ch, 0) + 1
        return char_freq

    # Get the frequencies of each character in the text
    functools.reduce(getcharfreq, text, char_freq)

, где текст - это длинная строка из многих символов. char_freq - это словарь, в котором ключ является символом, а его значением является его частота в тексте.

Однако я не уверен, как go получить удвоение или утроение символа без использования итерация первая. Например, если бы мой текст был «Я Джимми», двойное значение было бы следующим:

«I»,

«am»,

«J»,

"im",

"my"

Тройки будут каждые 3 символа за раз. Было бы достаточно просто перебрать и добавить каждые 2 или 3 символа к list, затем передайте его в reduce (). Но поскольку я не могу выполнить итерацию, я в некоторой степени не понимаю, как это делать.

Я новичок в python в целом и новичок в концепции функционального программирования, поэтому прошу прощения, если ответ прост. Кроме того, если есть совершенно другой способ сделать это, эта идея будет оценена!

Ответы [ 2 ]

0 голосов
/ 08 мая 2020

Разрешено ли вам использовать рекурсию? Если это так, вы можете получить набор кортежей любой длины с помощью рекурсивной функции и функции map () для создания списка счетчиков:

def prefixes(s):
    return [s] + prefixes(s[:-1]) if s else []

def nTuples(s):
    return prefixes(s) + nTuples(s[1:]) if s else []

def tupleCounts(s):
    tuples = nTuples(s)
    return list( map(lambda t:(t,tuples.count(t)), set(tuples)) )

Обратите внимание, что это подсчитывает перекрывающиеся кортежи (например. ana засчитывается дважды, потому что он перекрывает себя в anana)

, если вам нужны только 2-кортежи и 3-кортежи, вы можете добавить фильтр к назначению tuples переменная в tupleCounts()

вывод:

tupleCounts("banana")

[('a', 3),      ('ana', 2),   ('nan', 1),  ('nana', 1), ('bana', 1), 
 ('banana', 1), ('banan', 1), ('anan', 1), ('na', 2),   ('n', 2),
 ('an', 2),     ('ba', 1),    ('b', 1),    ('ban', 1),  ('anana', 1)]
0 голосов
/ 07 мая 2020

Вот вспомогательная функция для создания всех групп размером n в последовательности.

def generate_n(seq, n, i, acc):
    if i >= len(seq):
        return acc
    else:
        acc.append(seq[i:i+n])
        return generate_n(seq, n, i + n, acc)

Обратите внимание, это не чисто функционально, потому что я использую .append, но без него вам пришлось бы использовать конкатенацию списков, что здесь очень неэффективно ... В общем, Python не предоставляет много эффективных структур для работы с типичными конструкциями чисто функционального программирования. Но чтобы быть «чисто функциональным», вы можете использовать:

def generate_n(seq, n, i, acc):
    if i >= len(seq):
        return acc
    else:
        return generate_n(seq, n, i + n, acc + [seq[i:i+n]])

Обратите внимание: Python не оптимизирует хвостовую рекурсию, поэтому это решение ограничено размером вашего стека (глубина более 1000 будет сложной. ). Но это было бы для упражнения (и вы бы никогда не писали бы такой код в производственной среде Python).

В любом случае, вот он в действии:

In [1]: def generate_n(seq, n, i, acc):
   ...:     if i >= len(seq):
   ...:         return acc
   ...:     else:
   ...:         acc.append(seq[i:i+n])
   ...:         return generate_n(seq, n, i + n, acc)
   ...:

In [2]: generate_n("I am Jimmy", 2, 0, [])
Out[2]: ['I ', 'am', ' J', 'im', 'my']

In [3]: generate_n("I am Jimmy", 3, 0, [])
Out[3]: ['I a', 'm J', 'imm', 'y']

In [4]: generate_n("I am Jimmy", 1, 0, [])
Out[4]: ['I', ' ', 'a', 'm', ' ', 'J', 'i', 'm', 'm', 'y']

Решение затем сводится к подсчету для каждого n 1-> 3.

...