3

I can't imagine I'm going to get much help from this due to my inability to explain it. But for instance I have a string like so:

s = "[1,[2,2,[3,4]],5]"

and I need to convert it into a nested list item as such

lst = ["1",["2","2",["3","4"]],"5"]

that if I were to go lst[1][2][0] it would return '3'.

The way I have tried to do it was by creating a substring for every number within '[' and end of string characters and then slowly nest it back up

def ParseList(strlist):
    if '[' in strlist:
        print strlist
        return ParseList(GetBetweenChar(strlist,'[',None))
    else:
        return strlist

however it returns:(which although maybe a good start? I dont know where to continue)

[1,[2,2,[3,4]],5]
 1,[2,2,[3,4]],5
 2,2,[3,4]],
 3,4]]

which I would think I would append that to a list item but I dont know how to..

  • sorry my fault I implied the input would only be integers rather it has to be able to feature strings,characters,booleans and integers for example: lst = ["x",["2","2",["True","4"]],"5"] – Evan Maltby Oct 31 '17 at 04:02

5 Answers5

2

You can use ast.literal_eval to safely convert the string to a nested list of integers. Then define a nested map function to convert to all elements to strings, whilst maintaining the nesting structure.

from ast import literal_eval
s = "[1,[2,2,[3,4]],5]"
ls = literal_eval(s)

# yes I know there is something else called nmap 
def nmap(fn, iterable):
    res = []
    for i in iterable:
        if isinstance(i, list): # could be tuple or something else?
            res.append(nmap(fn, i))
        else:
            res.append(fn(i))
    return res

result = nmap(str, ls)

print(result)
print(result[1][2][0])

result:

['1', ['2', '2', ['3', '4']], '5']
3

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
  • Okay. This works for numbers, but to be fair I wasent upfront with what input will be passing through, the integers as the input were just a test instead all means of data types will be put in such as strings,booleans and integers. which returns a malformed string error. How can I allow this to also accept other data types? – Evan Maltby Oct 31 '17 at 03:58
  • 1
    Can you add an example to your question, so I can try to reproduce the error myself? – Paul Rooney Oct 31 '17 at 03:59
  • How do you mean by example? like a use case or? I just commented on my own question what the input could look like if thats what you mean. :) – Evan Maltby Oct 31 '17 at 04:05
  • Yes that is what i meant. The example in your comment above is a list, whereas the original example is a string. So which is it? If `lst = ["x",["2","2",["True","4"]],"5"] ` were the input, what would be the expected output? – Paul Rooney Oct 31 '17 at 04:15
  • that would be the output. so Input: `"[x,[2,2,[True,4]],5]"` Output: `["x",["2","2",["True","4"]],"5"]` sorry for the confusion on my part – Evan Maltby Oct 31 '17 at 04:21
  • 1
    Are you sure? why not `"['x',[2,2,[True,4]],5]"` (the `x` value is quoted). Without the quotes, it would interpret `x` as a variable called `x` and would complicate the requirements to parse it. – Paul Rooney Oct 31 '17 at 04:29
  • Thank you that does work, however I am not using this input to evaluate anything within the actual program. So it would be perferred to be able to just enter x rather than 'x' as it is reading from a file for input. should I just add ' ' before the evaluation(in order it to not be read as a variable) or is there another way around? – Evan Maltby Oct 31 '17 at 04:35
  • 1
    If you can add the quotes it means a solution like I have here, could work. If not then you'll have to do the parsing yourself. You'd have to split the string on brackets and commas and try the different possible conversions and if `int` or `bool` failed you could fall back on string. It's not entirely trivial and is introduces some ambiguities (e.g. is `True` the boolean `True` or the string `"True"`). Perhaps I'm over complicating it, but it seems to be a lot harder without the quotes. – Paul Rooney Oct 31 '17 at 04:45
  • I was able to make do with the ' ' method. Thank you so much for your help! – Evan Maltby Oct 31 '17 at 05:11
0

You can use eval(). Just be careful to make sure the string is safe because eval will convert a string to valid python code.

>>> eval("[1,[2,2,[3,4]],5]")[1][2][0]
3

Some more info: What does Python's eval() do?

Qwertie
  • 5,784
  • 12
  • 45
  • 89
0

If you didn't require every piece to be a string, but you could let numbers be numbers, then you can use the json library:

>>> s = "[1,[2,2,[3,4]],5]"
>>> import json
>>> json.loads(s)
[1, [2, 2, [3, 4]], 5]

Notice that if your original list contains numbers or booleans, they will stay as numbers or booleans. This is probably what you want, BUT if you really need everything to be strings, then you can recurse through the nested arrays and apply str to everything (look for "How to do flatmap in Python") or request further help in the comment section below.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • This also works just fine but only (as I said in my other comment by Paul) works with the integers, if I were to add a string or character into the list it returns ValueError: No JSON object could be decoded – Evan Maltby Oct 31 '17 at 04:01
  • Well that error would only occur if you single-quoted the strings. If the strings inside were double quoted, such as `'["abc", 1]'` then it would work. Can I ask whether your expected input will have quoted strings, or will the tokens be unquoted? And what about commas? Can the values themselves have commas? Getting this exactly right can be very tricky, but if you can fully specify expected inputs and outputs I would be happy to help – Ray Toal Oct 31 '17 at 05:42
0

You could proceed by first adding the quotes around the digits, then eval the list:

s = "[1,[2,2,[3,4]],5]"
res = ''
for c in s:
    if c.isdigit():
        res += '"' + c + '"'
    else:
        res += c

s = eval(res)
s

output:

['1', ['2', '2', ['3', '4']], '5']

This will work for single digit numbers; a little bit more work would be needed for multiple digits, or floats

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
0

Eval is not safe for user input.

You can do something like for python (2.6+):

>>> import ast
>>> s = "[1,[2,2,[3,4]],5]"
>>> lst = ast.literal_eval(s)
>>> str(lst[1][2][0])
'3'
Rajan
  • 1,463
  • 12
  • 26