"""
some recursive functions on nested lists
"""


def depth(obj):
    """
    Return 0 if obj is a non-list, or 1 + maximum
    depth of elements of obj, a possibly nested
    list of objects.

    Assume obj has finite nesting depth

    @param list[object]|object obj: possibly nested list of objects
    @rtype: int

    >>> depth(3)
    0
    >>> depth([])
    1
    >>> depth([[], [[]]])
    3
    >>> depth([1, 2, 3])
    1
    >>> depth([1, [2, 3], 4])
    2
    """
    if obj == []:
        return 1
    elif not isinstance(obj, list):
        return 0
    else:
        return 1 + max([depth(i) for i in obj])


def rec_max(obj):
    """
    Return obj if it's an int, or the maximum int in obj,
    a possibly nested list of numbers.

    Assume: obj is an int or non-empty list with finite nesting depth,
    and obj doesn't contain any empty lists

    @param int|list[int|list[...]] obj: possibly nested list of int
    @rtype: int

    >>> rec_max([17, 21, 0])
    21
    >>> rec_max([17, [21, 24], 0])
    24
    >>> rec_max(31)
    31
    """
    if not isinstance(obj, list):
        return obj
    else:
        return max([rec_max(i) for i in obj])


def flatten(S):
    """
    Flatten a list of lists to a list of depth 1
    @param list[list] S: The list of lists
    @rtype: list

    >>> flatten([1, 2, [3, 4, [5]]])
    [1, 2, 3, 4, 5]
    """
    if not isinstance(S, list):
        return [S]
    else:
        return sum([flatten(i) for i in S],[])


def concat_strings(string_list):
    """
    Concatenate all the strings in possibly-nested string_list.

    @param list[str]|str string_list:
    @rtype: str

    >>> concat_strings("brown")
    'brown'
    >>> concat_strings(["now", "brown"])
    'nowbrown'
    >>> concat_strings(["how", ["now", "brown"], "cow"])
    'hownowbrowncow'
    """
    if not isinstance(string_list, list):
        return str(string_list)
    else:
        return "".join([concat_strings(i) for i in string_list])


if __name__ == '__main__':
    import doctest
    doctest.testmod()