在对列表进行双重递归时,“预检查”是避免添加无类型或空字符串的首选方法吗?

Posted

技术标签:

【中文标题】在对列表进行双重递归时,“预检查”是避免添加无类型或空字符串的首选方法吗?【英文标题】:Is "pre-checking" the preferred way to avoid adding None-types or empty strings when doing double recursion on lists? 【发布时间】:2019-07-15 22:46:47 【问题描述】:

我正在 python3 中对列表进行一些递归练习,遇到了一个问题,我的返回列表中会填充一些不需要的 None 类型。

这个特殊的练习是为了创建一个从列表中删除所有元音字符串的函数。输入列表中的所有元素都是长度为 1 的字符串,但列表也可以包含更多列表。

def without_vowels(arg):
    vowels = "aeiuoåäöAEIUOÅÄÖ"

    if not arg:
        return arg

    elif isinstance(arg, str):
        if not arg in vowels:
            return arg
        else:
            return ""

    elif isinstance(arg, list):
        if without_vowels(arg[0]) == "":
            return without_vowels(arg[1:])
        else:
            return [without_vowels(arg[0])] + without_vowels(arg[1:])

预期输出:

>>> test = ["a", ["h", "e", "j"], ["t", "e", "s", "c", "o"]]
>>> without_vowels(test)
>>> [['h', 'j'], ['t', 's', 'c']]

最初,为了“删除”检测到的元音,我根本不会返回任何东西。这导致无类型被添加到列表中。

没有变通方法的输出(删除第 10,11、14-16 行):

>>> without_vowels(test)
>>> [None, ['h', None, 'j'], ['t', None, 's', 'c', None]]

为了解决这个问题,我更改了代码以在找到元音时返回一个空字符串,并在再次调用函数以继续之前添加了“预检查”,基本上只是检查函数调用是否会找到元音(并返回“”)并在这种情况下跳到列表参数的下一部分。

我觉得我遗漏了一些明显的东西,应该有一个更好的解决方案,而不使用这样的解决方法。

谢谢

编辑:这个特殊的练习是用双递归解决的,而不是迭代和单递归的组合

【问题讨论】:

【参考方案1】:

这个特殊的练习是用双重递归来解决的, 不是迭代和单次递归的结合

我的递归方法是保持简单,让递归为您完成工作:

VOWELS = set("aeiuoåäöAEIUOÅÄÖ")

def without_vowels(argument):

    if not argument:
        return argument

    head, *tail = argument

    if isinstance(head, list):
        head = without_vowels(head)
    elif head in VOWELS:
        return without_vowels(tail)

    return [head, *without_vowels(tail)]

用法

>>> test = ["a", ["h", "e", "j"], ["t", "e", "s", "c", "o"]]
>>> without_vowels(test)
[['h', 'j'], ['t', 's', 'c']]
>>> 

【讨论】:

【参考方案2】:

这取决于您想要什么“更好的解决方案”。我认为最直接的方法是从你遇到的任何东西中删除元音,重复出现在序列元素上。我做了一步:

def without_vowels(arg):
    vowels = "aeiuoåäöAEIUOÅÄÖ"
    if not isinstance(arg, list):
        return arg

    result = [c for c in arg if not isinstance(c, str) or c not in vowels]
    for idx, c in enumerate(result):
        if isinstance(arg, list):
            result[idx] = without_vowels(result[idx])

    return result

test = ["a", ["h", "e", "j"], ["t", "e", "s", "c", "o"]]
print( without_vowels(test) )

输出:

[['h', 'j'], ['t', 's', 'c']]

我不知道它(还)比你的干净,但它确实避免了直接插入然后删除空元素。

【讨论】:

【参考方案3】:

我试图在一个单一的列表理解中实现它,但我太累了,无法让它工作。

这是我对您的问题的解决方案:

def without_vowels(arg):
    vowels = "aeiuoåäöAEIUOÅÄÖ"
    returnList = []
    for entry in arg:
        if type(entry) == str and entry not in vowels:
            returnList.append(entry)
        elif type(entry) == list:
            returnList.append(without_vowels(entry))
    return returnList

test = ["a", ["h", "e", "j"], ["t", "e", "s", "c", "o"]]
print(without_vowels(test))

以及上面代码的输出:

>>> without_vowels(test)
[['h', 'j'], ['t', 's', 'c']]

编辑:如果列表中唯一的条目是元音,我想我的解决方案会返回一个空列表,但如果没关系,那么这应该可以完成工作。

【讨论】:

是的,当列表参数中的唯一元素是元音时,返回一个空列表应该没问题。【参考方案4】:

我认为以下实现使您的问题没有实际意义:

VOWELS = set("aeiuoåäöAEIUOÅÄÖ")

def without_vowels(arg):
    if isinstance(arg, list):
        return [without_vowels(item) for item in arg if without_vowels(item)]
    elif isinstance(arg, str):
        non_vowels = [ch for ch in arg if ch not in VOWELS]
        if len(non_vowels) > 2:
            return non_vowels
        elif len(non_vowels) == 1:
            return non_vowels[0]
        return non_vowels

test = ["a", ["h", "e", "j"], ["t", "e", "s", "c", "o"]]

print(without_vowels(test))  # -> [['h', 'j'], ['t', 's', 'c']]

【讨论】:

以上是关于在对列表进行双重递归时,“预检查”是避免添加无类型或空字符串的首选方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

在对对象进行操作时链接递归 RxJS 可观察对象

java List递归排序,无序的列表按照父级关系进行排序(两种排序类型)

在 Yesod 中强制 Julius 重新插值或如何避免在客户端繁重的应用程序中对服务器进行双重标记

paypal如何避免PDT数据的双重回复

如何避免多线程在Oracle中进行双重插入

通过在运行时在泛型方法中进行类型转换来使用递归函数