Search code examples
pythonpython-3.xstringlistsublist

How can I convert a list of sublists including sublits to a string in Python


I would like to convert the following list of sublists inluding sublits including int to a string like the following:

[[[0], [0], [0], [0], [0], [0], '\n'], [[0], [1], [0], [0], [0], [0], '\n'], [[0], [0], [0], [0], [0], [0], '\n'], [[0], [0], [0], [0], [0], [0]]]

should be:

"000000\n
010000\n
000000\n
000000"

I already tried many different ways using .join and str using list compressions and etc. but I couldn't find a solution yet. I'd appreciate any help.

.join() looking in py doc


Solution

  • tl;dr. One-liner is

    ''.join(''.join(''.join(str(i) for i in x) for x in y) for y in l)
    

    Explanation

    Backtrack reasoning: if you want to use .join on a list of list of list (that is, or almost so, what you have), then you need first to convert each of those list of list into strings

    Which you can do also with .join. But to convert those list of list into string with .join, you need first to convert each of those list to string.

    And there is a trick. Firstly, not all of those lists are really lists. Some are [0], but some other are \n. But it doesn't really matter: both are iterable. String \n can be iterated. And you need to convert 0 into '0', which you can do with str. str that will be of no harm over \n (str('\n') is just '\n'. So str is not needed for those, but not harmful neither).

    So each of those [0] or '\n', can be treated as list of elements, to convert with str. Like this: [str(i) for i in x] is ['0'] or ['\n'] if x is [0] or '\n'.

    So ''.join(str(i) for i in x) is '0' or '\n' if x is [0] or '\n' (that's a bit overkill if we know for sure that those are always singleton, but you haven't said that).
    [Side note (you can ignore it if you're not interested in those details): I skipped the outer [, ] when joining. Because .join don't need an actual list: an iterable does. So, I'll do this in the following steps either: each time I get an itermediary result in the form of a compound list like [x for x in ...], I'll replace it by a compound iterable when passing it the join in the next step like ''.join(x for x in ...). It is easier with list in the first step, to debug and see content. For this problem it doesn't really matter. But generally speaking, it is always better to use compound iterable rather than compound list, when we don't actually need a list. A list takes place in memory. An iterable doesn't]

    To do this for all [0], [1] or '\n' of a list y of those, we can use another compound

    [''.join(str(i) for i in x) for x in y] is y is [[0], [0], [0], [0], [0], [0], '\n']:
    ['0', '0', '0', '0', '0', '0', '\n']
    [That is just previous line of code, embedded in another compound list. ... turned into [... for x in y]]

    You can join that easily
    ''.join(''.join(str(i) for i in x) for x in y) is
    '000000\n'

    You can do that for all list of your list: if l is [[[0], [0], [0], [0], [0], [0], '\n'], [[0], [1], [0], [0], [0], [0], '\n'], [[0], [0], [0], [0], [0], [0], '\n'], [[0], [0], [0], [0], [0], [0]]] (your list), then

    [''.join(''.join(str(i) for i in x) for x in y) for y in l] is
    ['000000\n', '010000\n', '000000\n', '000000']

    You can, finally join that ''.join(''.join(''.join(str(i) for i in x) for x in y) for y in l) is
    '000000\n010000\n000000\n000000'

    Hence my one-liner

    ''.join(''.join(''.join(str(i) for i in x) for x in y) for y in l)