function that returns elements in nested lists

Viewed 189

So this is the exercise that I've been given:

 def unflatten(ls):
    """returns elements in nested lists where the last element is None
    
    ls = list with string elements
    Examples:

    >>> unflatten(['Hello', 'world'])
    ['Hello', ['world', None]]
    >>> unflatten(['Hello'])
    ['Hello', None]
    >>> unflatten(['No', 'more', 'cherries', 'please!'])
    ['No', ['more', ['cherries', ['please!', None]]]]
    """
    """write your code here"""

So I wrote this:

newls = []
    x = 0
    for x in range(len(ls)):
        if x==0:
            newls.append(ls[x])
        elif x == len(ls)-1:
            newls.append([ls[x], None])
        else:
            newls.append([ls[x], ])
    print(newls)

which is correct only for a list of 2 elements Could someone suggest any answers ??

4 Answers

Maybe I am overlooking things, but doesn't this simple recursive approach suffice:

def unflatten(ls):
    if ls:
       return [ls[0], unflatten(ls[1:])]

>>> unflatten(['Hello', 'world'])
['Hello', ['world', None]]
>>> unflatten(['Hello'])
['Hello', None]
>>> unflatten(['No', 'more', 'cherries', 'please!'])
['No', ['more', ['cherries', ['please!', None]]]]

There are many ways to dress up this horse in a more or less readable /explicit fashion, for a one-liner you can include a conditional expression:

def unflatten(ls):
    if ls:
       head, *tail = ls
       return [head, unflatten(tail)]
    return None  # not necessary

def unflatten(ls):
    return [ls[0], unflatten(ls[1:])] if ls else None

Here is a simple solution using recursion:

def unflatten(lst):
    if not lst:
        return None
    return [lst[0], unflatten(lst[1:])]
>>> unflatten(['No', 'more', 'cherries', 'please!'])
['No', ['more', ['cherries', ['please!', None]]]]
def unflatten(ls):
    val = None
    for word in reversed(ls):
        val = [word, val]
    return val

Or, even shorter:

from functools import reduce

def unflatten(ls):
    return reduce(lambda v, w: [w, v], reversed(ls), None)

The recursive solutions look better then doing it iteratively - buy you still can do that:

def unflatten(ls):
    """returns elements in nested lists where the last element is None"""
    if isinstance(ls, list) and ls:
        # create list with first element if ls is not empty
        rv = [None if not ls else ls[0]]
        # remember the outermost list that we return
        rvv = rv
        # add an empty list at end
        rv.append([])
        for e in ls[1:]:
            # set rv to be the empty list at the end and add value
            rv = rv[-1]
            rv.append(e)
            # add another empty list
            rv.append([])
        # replace empty list at end by None
        rv[-1] = None    
        return rvv
    else:
        return ls # not a list - could raise an exception as well


print(unflatten(['Hello', 'world']))
print(['Hello', ['world', None]])

print(unflatten(['Hello']))
print(['Hello', None])

print(unflatten(['No', 'more', 'cherries', 'please!']))
print(['No', ['more', ['cherries', ['please!', None]]]])

Output:

['Hello', ['world', None]]
['Hello', ['world', None]]
['Hello', None]
['Hello', None]
['No', ['more', ['cherries', ['please!', None]]]]
['No', ['more', ['cherries', ['please!', None]]]]
Related