以空格分隔相邻的相同字符的递归函数

时间:2018-10-31 13:58:42

标签: python python-3.x recursion

如何编写一个带有字符串参数并返回一个字符串的递归函数,该字符串的相邻相同字符之间用空格分隔?

我编写了一个非递归函数,该函数可以实现我想要的功能:

def space_adj(istr):
    new_str = ''
    delimiter = ' '
    for i, ch in enumerate(istr[:len(istr)-1]): 
        if ch == istr[i+1]:
            new_str += ch + delimiter 
        else:
            new_str += ch
    new_str += istr[-1]
    return new_str

我希望它这样做:

>>> space_adj('abcdeffghhh')
'abcdef fgh h h'

3 个答案:

答案 0 :(得分:1)

实际上不需要进行递归,但是可以这样进行:

delimiter = " "

def space_adj(istr):
    if len(istr) < 2:  # The end-condition for the recursion
        return istr
    result = space_adj(istr[:-1])  # Get result for the shorter string with recursion
    if istr[-1] == istr[-2]:
        return result + delimiter + istr[-1]
    else:
        return result + istr[-1]

请注意istr[:-1]的较短语法istr[:len(istr)-1]

仅提及一种不相关的替代方法:您可以使用一个正则表达式替换来完成此操作:

import re
def space_adj(istr):
    return re.sub(r"(\w)(?=\1)", r"\1 ", istr)

答案 1 :(得分:1)

您可以使用像这样的典型基数和归纳案例设计递归函数-

def space_adj (s, delim = " "):
  # base case: one char or less
  if len(s) < 2:
    return s
  # inductive case 1: at least two chars
  elif s[0] == s[1]:
    return s[0] + delim + space_adj(s[1:], delim)
  # inductive case 2: at least two unmatching chars
  else:
    return s[0] + space_adj(s[1:], delim)

Python在许多基本操作中都使用了符号语法,但我认为这总体上损害了程序的可读性-

def first (x):
  return x[0]

def second (x):
  return x[1]

def tail (x):
  return x[1:]

def space_adj (s, delim = " "):
  if len(s) < 2:
    return str
  elif first(s) == second(s):
    return first(s) + delim + space_adj(tail(s), delim)
  else:
    return first(s) + space_adj(tail(s), delim)

程序的每个版本的输出都是相同的-

print(space_adj("abcdeffghhh"))
# "abcdef fgh h h"

print(space_adj("a"))
# "a"

print(space_adj(""))
# ""

或尝试使用辅助功能将问题分解为更小的部分。下面我们不得不编写两个函数,而不仅仅是一个,但是每个函数都是

  • 更容易写
  • 更容易阅读
  • 更易于测试/调试/维护
def join (a, b, delim = " "):
  if a == b:
    return a + delim
  else:
    return a

def space_adj (s):
  if len(s) < 2:
    return s
  else:
    return join(s[0], s[1]) + space_adj(s[1:])

print(space_adj("abcdeffghhh"))
# "abcdef fgh h h"

递归是一种功能性遗产,因此最好在其自然环境中学习递归。在上方您可以看到space_adj只是一台简单的机器-

space_adj("abcde")
    = join("a","b")
        + join("b","c")
            + join("c","d")
                + join("d","e")
                    + "e"

这意味着space_adj本身可以作为通用函数,只要我们将join设为参数。在下面,我们为联接命名space_between_same。现在我们有了通用的joiner函数-

def space_between_same (a, b):
  if a == b:
    return a + " "
  else:
    return a

def joiner (s, join = space_between_same):
  if len(s) < 2:
    return s
  else:
    return join(s[0], s[1]) + joiner(s[1:], join)

print(joiner("abcdeffghhh"))
# "abcdef fgh h h"

现在我们可以指定如何进行联接,我们可以看到高阶函数的功能和灵活性-

joiner("CamelToTitleCase", lambda a, b: a + " " if b.isupper() else a)
# "Camel To Title Case"

joiner("CamelToSnakeCase", lambda a, b: a.lower() + "_" if b.isupper() else a.lower())
# "camel_to_snake_case"

joiner("reemoveed duplicatees", lambda a, b: "" if a == b else a))
# "removed duplicates"

joiner([ 1, 2, 2, 3, 3, 3 ], lambda a, b: [] if a == b else [a]))
# [ 1, 2, 3 ]

以上,space_between_same硬编码" "分隔符。我们可以制作另一个高阶函数between_same以使分隔符可以由用户配置-

def between_same (delim = ""):
  def join (a, b):
    if a == b:
      return a + delim
    else:
      return a
  return join

def joiner (s, join = between_same(" ")):
  if len(s) < 2:
    return s
  else:
    return join(s[0], s[1]) + joiner(s[1:], join)

print(joiner("abcdeffghhh")) # default
# "abcdef fgh h h"

print(joiner("abcdeffghhh", between_same("=")))
# "abcdef=fgh=h=h"

以这种方式解决问题产生了一个截然不同的程序,但是如您所见,我们可以将程序定向到许多理想的结果,而复杂度几乎为零。


相关:上面的joinerfold类似但不相同。

答案 2 :(得分:0)

自从您标记了[python-3.x]这个问题以来,让我们使用Python-3-ism:

def space_adj(istr):
    if not istr:
        return istr

    first, *second_on = istr

    if not second_on:
        return first

    second, *_ = second_on

    return first + ['', ' '][first == second] + space_adj(second_on)

这里的一个窍门是我们将参数视为序列,而不是 str 。递归时,参数变为 list ,但它仍然是一个序列,因此一切正常。