Python Forum
Thread Rating:
  • 2 Vote(s) - 3 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Recursivity - Problem
#1
Hi, I got a problem this code :

def deepconcat(l) :
    if l == [] :
        return None
    elif len(l) == 1 :
        return l[0]
    else :
        for i in l :
            if type(i) == str :
                return l[0] + deepconcat(l[1:])
            if type(i) == list :
                return deepconcat(i+l[1:]) 
I have to turn ["a",["b","6"],"e",["5",["g","h"]],"i"] into "ab6e5ghi".
It works.
If I add a string at the end of the list, for example : ["a",["b","6"],"e",["5",["g","h"]],"i","o"], it works.
But when I add a sub list, for example : ["a",["b","6"],"e",["5",["g","h"]],"i",["k"]], I have a TypeError.
I don't understand why, could you please help me ?
Reply
#2
What's the whole error?
Reply
#3
+1 to nilamo requesting the whole error, but I felt generous and ran the code:
Error:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 9, in deepconcat File "<stdin>", line 11, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 11, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 11, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 9, in deepconcat File "<stdin>", line 9, in deepconcat TypeError: can only concatenate str (not "list") to str
When I started digging into your code I realized that you're returning within a loop such that the loops is misleading, you only ever look at the first element (for input composed only of strings and lists). I would suggest that you either (1) get rid of that loop or (2) make the loop not return on the first iteration. I think once you do that that your code will be more clear and easier for you and us to debug.
Reply
#4
x =  ["a",["b","6"],"e",["5",["g","h"]],"i"]
x.__repr__().replace("[",'').replace("]". '').replace("'",'').replace(" ",'')
Reply
#5
scidam that's an interesting solution but it's less generic given an input like so:
['"', "a", '"']
For the original poster - a heavier hint is that you should trace your code for the following input:
[["1"]]
Reply
#6
I just ran the code with ['"', "a", '"'] as input and it works fine for me, I got: '"a"'. It also works for deeply nested lists. In any case I am agreeing with that the recursive traversing this nested structure is more generic.
Reply
#7
Some observations:

- function can return three different datatypes: None, int and str. Whatever usage follows, it must be very defensive (None if empty list, int if list with one integer, string as expected result)

- for me personally it's more natural to return only one datatype. In case of empty list it should be empty string

- it works only when elements are strings, otherwise TypeError will be raised

It's of course upon specific needs but nevertheless I would have solved this problem differently. I would have separated flattening the list and manipulating list elements.

I would have created stream of elements of flattened list:

def flat_stream(lst):
    for item in lst:
        if isinstance(item, (list, tuple)):
            yield from flat_stream(item)
        else:
            yield item


This returns generator object which is memory efficient. It preserves all elements in their original type (which is often needed).

Now I can manipulate this stream whatever way I want:

>>> ls = ["a",["b","6"],"e",["5",["g","h"]],"i",["k"]]
>>> ''.join(el for el in flat_stream(ls))
'ab6e5ghik'
>>> list(flat_stream(ls))
['a', 'b', '6', 'e', '5', 'g', 'h', 'i', 'k']
If there are different types of elements and I want to manage them differently (data often needs verifying, cleansing etc) then I can do it:

>>> ls = ["a",("b","6"),"e",[5,["g","h"]],"i",["k"]]                 # there is int and tuple in list
>>> ''.join(str(el) for el in flat_stream(ls))                       # convert all elements to str
'ab6e5ghik'
>>> ''.join(el for el in flat_stream(ls) if isinstance(el, str))     # ignore int
'ab6eghik'
>>> [el for el in flat_stream(ls) if not isinstance(el, str)]        # ignore strings
[5]
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020