【问题标题】:How to write a recursive function that takes a list and return the same list without vowels?如何编写一个递归函数,它接受一个列表并返回没有元音的相同列表?
【发布时间】:2017-02-03 20:53:56
【问题描述】:

我应该编写一个递归函数,它接受一个字符串列表或一个字符串列表列表,如果找到,则返回不带元音的列表。这是我解决它的尝试:

def noVow(seq):
    keys = ['a','i','e','o','u','u']
    if not seq or not isinstance(seq, list) :
        return 
    else:
        if seq[0]  in keys:
            del seq[0]
            return (noVow(seq[0:]))
        else:
            return (noVow(seq[1:]))


li = ["b", "c", "d","a"]
print (noVow(li))

我知道错误存在于我的基本情况中,但是我无法提出正确的基本情况。

请注意,递归函数必须用纯函数式编程编写,即不允许有副作用。

【问题讨论】:

  • 不相关,但为什么你的字母 u 出现了两次?
  • @Hoopdady 你说得对,非常不相关!
  • del seq[0] 不会被视为一种副作用,它否定了避免可变数据的纯函数式编程?只是想了解您的需求是否相互交叉。
  • @cdlane 实际上我不确定,我更像是一个命令式编程程序员,而且我对整个函数式编程概念都是新手。所以是的,你可能是对的。因为它会产生副作用,所以它不应该存在。

标签: python recursion functional-programming


【解决方案1】:

我相信这个解决方案在没有任何外部帮助的情况下正确地实现了“字符串列表或字符串列表”和“返回相同的列表”这两个标准:

def noVowels(sequence, index=0):
    if not (sequence and type(sequence) is list and index < len(sequence)):
        return 

    vowels = {'a','i','e','o','u'}

    if type(sequence[index]) is list:
        noVowels(sequence[index])
    elif sequence[index] in vowels:
        del sequence[index]
        index -= 1

    noVowels(sequence, index + 1)

    return sequence

测试

array = [['a', 'b', 'c', 'd', 'e'], 'f', 'g', 'h', 'i', ['l', 'm', ['n', 'o', 'p'], 'q'], 'r', 's', 't', 'u']

print(array)
print(id(array))
print(id(array[0]))

result = noVowels(array)

print(result)
print(id(result))
print(id(result[0]))

结果

> python3 test.py
[['a', 'b', 'c', 'd', 'e'], 'f', 'g', 'h', 'i', ['l', 'm', ['n', 'o', 'p'], 'q'], 'r', 's', 't', 'u']
4315447624
4315344520
[['b', 'c', 'd'], 'f', 'g', 'h', ['l', 'm', ['n', 'p'], 'q'], 'r', 's', 't']
4315447624
4315344520
>

请注意,相同的列表和内部列表基于其 id 不变而保持不变。它处理列表列表的列表。

我不相信它是函数式程序,因为它会产生副作用,但这种矛盾是 OP 问题描述中固有的。

【讨论】:

    【解决方案2】:

    要处理包含字符串的列表列表和平面字符串列表,您需要遍历序列,然后检查类型:

    def noVow(seq):
        vowels = {'a', 'i', 'e', 'o', 'u', 'u'}
        for ele in seq:
            if isinstance(ele, list):
                # a list so recursively process
                yield [s for s in noVow(ele)]
            # else it has to be a string so just see if it is not a vowel
            elif ele not in vowels:
                yield ele
    

    你像这样使用它:

    In [39]: li
    Out[39]: [['b', 'c'], ['d', 'a']]
    
    In [40]: li[:] = noVow(li)
    
    In [41]: print(li)
    [['b', 'c'], ['d']]
    
    In [42]: li = ["a","b","c","e"]
    
    In [43]: li[:] = noVow(li)
    
    In [44]: print(li)
    ['b', 'c']
    In [10]: li = [["b", "c"], ["d", ["a"]]]
    In [11]: li[:] = noVow(li)   
    In [12]: li
    Out[12]: [['b', 'c'], ['d', []]] # works for nested lists
    

    如果你想要一个所有非元音的平面列表并且你可以使用 python3,你可以使用 yield from:

    def noVow(seq):
        vowels = {'a', 'i', 'e', 'o', 'u', 'u'}
        for ele in seq:
            if isinstance(seq, list):
                yield from noVow(ele)
            elif ele not in vowels:
                yield ele
    

    你用同样的方式:

    In [2]: li = [["b", "c"], ["d", "a"]]
    
    In [3]: li[:] = noVow(li)
    
    In [4]: li
    Out[4]: ['b', 'c', 'd']
    
    In [5]: li = ["a","b","c","e"]
    
    In [6]: li[:] = noVow(li)
    
    In [7]: li
    Out[7]: ['b', 'c']
    

    你可以用 python2 做同样的事情,你只需要另一个循环

    【讨论】:

    • 只是为了分类,而不是批评:在“字符串列表或字符串列表”和“返回相同的列表”这两个突出标准中,您的标准可以很好地处理这两种情况,但前提是你使用li[:] = noVow(li)的外部协助
    • @cdlane,它改变了原始列表,并且比在随机索引处删除对象更有效。如果我让某人编写一个递归函数来对任意对象进行操作,我会比我在这里看到的其他内容更高兴看到这个。
    【解决方案3】:

    您的基本情况返回无。因此,每当您传递空列表时,None 就会向上发送到递归调用堆栈。

    此外,您没有存储不是元音的字符,因此您的 else 情况是错误的。

    你可以拥有的是这样的:

    >>> def noVow(seq):
    ...     keys = ['a','i','e','o','u','u']
    ...     if not seq or not isinstance(seq, list) :
    ...         return []
    ...     else:
    ...         if seq[0] in keys:
    ...             return noVow(seq[1:])
    ...         else:
    ...             return [seq[0]] + noVow(seq[1:])
    

    同样seq[0:] 等价于seq。

    【讨论】:

    • 返回相同的不带元音的列表。如果你正在切片,你将不会有相同的列表。而且你会更好地理解
    • 是的,错过了相同的列表部分。
    • 只是为了分类,而不是批评:在“字符串列表或字符串列表”和“返回相同列表”这两个突出标准中,您的这两种情况都不能处理。
    【解决方案4】:

    返回 same 没有元音的列表

    嗯,你在递归调用中切片原始列表,所以你有一个副本不一样的列表。

    更重要的是,您的代码确实有效,但由于您传递了列表的 slice,因此切片中的元音项目(不是原始列表)被删除,而原始代码保持不变。

    您可以改为使用从 start 移动到 end 原始列表索引的 non-slicing 变体:

    def no_vow(seq, index=0):
        keys = ['a','i','e','o','u']
        if not seq or not isinstance(seq, list) or index >= len(seq):
            return 
        else:
            if seq[index] in keys:
                del seq[index]
                return no_vow(seq, index)
            else:
                return no_vow(seq, index+1)
    

    最后,如果要打印结果,则不应打印函数调用的输出(将是 None),而是打印列表。


    试用:

    li = ["b", "c", "e", "d", "a"]
    
    no_vow(li) # list is modified in-place
    print(li)
    # ["b", "c", "d"]
    

    【讨论】:

    • 只是为了分类,而不是批评:在“字符串列表或字符串列表”和“返回相同列表”这两个显着标准中,您的返回相同的列表很好,但没有'不处理列表列表的情况。
    【解决方案5】:
    def no_vowel(seq):
        if not isinstance(seq, list):
            raise ValueError('Expected list, got {}'.format(type(seq)))
        if not seq:
            return []
        head, *tail = seq
        if isinstance(head, list):
            return [[no_vowel(head)]] + no_vowel(tail)
        else:
            if head in 'aeiou':
                return no_vowel(tail)
            else:
                return [head] + novowel(tail)   
    

    列表的酷解包是 Python 3 的一个特性,与函数式编程模式匹配非常相似。

    【讨论】:

    • 你在最后一行有一个错字novowel,应该是no_vowel
    • 只是为了分类,而不是批评:在“字符串列表或字符串列表”和“返回相同列表”这两个突出标准中,您的列表很好地处理了列表情况但不返回相同的列表,而是一个副本。
    • 原地修改列表不会造成副作用吗?
    • 我同意并在对 OP 问题文本的评论和我自己的答案文本中解决了这个问题。他要求的是矛盾的东西,不能全部满足。但是,即使有充分的理由,您选择忽略哪些标准也可能应该记录在您的答案中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 2010-10-20
    • 1970-01-01
    • 2011-05-12
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多