Designate a variable as a list without overwriting it in a function

梦想与她 提交于 2020-01-04 05:54:18

问题


I created a function that will flatten a nested list into an ordinary list.

outputarray = []

def flattenarray(x):
    for elmt in x:
        if isinstance(elmt, float) or isinstance(elmt, int):
            outputarray.append(elmt)
        elif isinstance(elmt, list):
            flattenarray(elmt)
    return outputarray

The above works perfectly, but I am trying to have the "outputarray" variable inside the function, but when I do, the recursion step will overwrite the outputarray list back into an empty list.

How can I make this work to designate a list inside the function and at the same time be able to append to it without overwriting it during recursion?


回答1:


You will want to create the output array from within the function. One way to proceed is to pass the output container along in the recursive step:

def flattenarray(x, outputarray=None):
    if outputarray is None:
        outputarray = []
    for elmt in x:
        if isinstance(elmt, float) or isinstance(elmt, int):
            outputarray.append(elmt)
        elif isinstance(elmt, list):
            flattenarray(elmt, outputarray=outputarray)
    return outputarray

A more Pythonic approach is for the flattener to yield the items one-by-one. Note that isinstance can accept a tuple of types, so you only need to call it once.

def flatten(x):
    for elmt in x:
        if isinstance(elmt, (int, float, str, bytes)):
            yield elmt
        else:
            yield from flatten(elmt)

A more correctly duck-typing implementation:

def flatten(x):
    try:
        it = iter(x)
    except TypeError:
        yield x
        return
    if isinstance(x, (str, bytes)):
        yield x
        return
    for elem in it:
        yield from flatten(elem)



回答2:


This works perfectly with one line function and the basic idea is the same with wim:

def flatten(lst, outputarray=[]):
    return sum( ([x] if not isinstance(x, (list,tuple))  else flatten(x)
                     for x in lst), outputarray)


lst=[1,2,3,[2,4,5,[6]],(7,8,9)]

print(flatten(lst))

Result:

[1, 2, 3, 2, 4, 5, 6, 7, 8, 9]



回答3:


You could use the return value of your recursive function calls to extend the output instead of trying to insert into a global variable:

def flattenarray(x):
    outputarray = []
    for elmt in x:
        if isinstance(elmt, float) or isinstance(elmt, int):
            outputarray.append(elmt)
        elif isinstance(elmt, list):
            outputarray.extend(flattenarray(elmt))
    return outputarray

This creates many more temporary lists than strictly necessary, so isn't very efficient. On the other hand, it's just as easy to read as your original code.

On a different note, I'd like to suggest a generalization to your code. Instead of checking for three specific types and skipping everything else, you can just check if an element is iterable or not:

global variable:

def flattenarray(x):
    outputarray = []
    for elmt in x:
        try:
            outputarray.extend(flattenarray(elmt))
        except TypeError:
            # the error will be raised by the for loop in the recursive call
            outputarray.append(elmt)
    return outputarray


来源:https://stackoverflow.com/questions/51489385/designate-a-variable-as-a-list-without-overwriting-it-in-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!