J.dlb
J.dlb

Reputation: 29

String of a list into a list

I'd like to find the quickest way to change a string of a list with a different types inside, into a list.

For example:

string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'

into

list = [['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]

I know that the module ast provides function that could help, but it only works when:

string = '[["Date1","Date2","Number1","Number2"],["28Dec2018","29Dec2018",1.24,5]]'

Thanks

Upvotes: 1

Views: 112

Answers (3)

DirtyBit
DirtyBit

Reputation: 16772

string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
print(string.strip("[]").split(","))

OUTPUT:

['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']

EDIT:

string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'


st = string.strip("[]").replace("[", "").replace("]", "").split(",")
listA = []
listB = []

c = 0
for s in st:
    c = c + 1
    if c <= 4:
        if s.isdigit():
          listA.append(int(s))
        elif re.match("^\d+?\.\d+?$", s):
            listA.append(float(s))
        else:
            listA.append(s)
    else:
        if s.isdigit():
            listB.append(int(s))
        elif re.match("^\d+?\.\d+?$", s):
            listB.append(float(s))
        else:
            listB.append(s)

print([listA, listB])

OUTPUT:

[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]

OR

If you don't want to convert the int and float then its even shorter:

for s in st:
    c = c + 1
    if c <= 4:
        listA.append(s)
    else:
        listB.append(s)    
print([listA, listB])

OUTPUT:

[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']]

OR

As suggested by @Bhathiya Perera in the comments, a one liner killer using yaml:

import yaml
print(yaml.safe_load(string))

Upvotes: 2

tobias_k
tobias_k

Reputation: 82899

You could use a regular expression to detect everything that does not seem to be a number. Then, re.sub all those non-numbers with themselves in quotes, i.e. `r'"\1"'

>>> string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'    
>>> re.findall(r"(?<=[,\[])(\w*[a-zA-Z]\w*)(?=[,\]])", string)
['Date1', 'Date2', 'Number1', 'Number2', '28Dec2018', '29Dec2018']
>>> re.sub(r"(?<=[,\[])(\w*[a-zA-Z]\w*)(?=[,\]])", r'"\1"', string)
'[["Date1","Date2","Number1","Number2"],["28Dec2018","29Dec2018",1.24,5]]'

This is a bit ugly, so let's break that down a bit:

  • (?<=[,\[]): preceeded by , or [
  • (\w*[a-zA-Z]\w*): letters or digits, actually a letter, and more letters or digits
  • (?=[,\]]): followed by , or ]

Now, your string is valid JSON1) and can be parsed as such with the json module:

>>> import json
>>> json.loads(_)
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]

This works for the examples given in your question. For other strings, the "letters or digits"-part of the regex would have to be revamped considerably. Alternatively, you might just wrap everything in quotes...

>>> re.sub(r"([^,\[\]]+)", r'"\1"', string)
"[['Date1','Date2','Number1','Number2'],['28Dec2018','29Dec2018','1.24','5']]"
>>> lst = json.loads(_)

... and then recursively cast to int or float whereever possible in a postprocessing step.

def try_to_cast(lst):
    for i, x in enumerate(lst):
        if isinstance(x, list):
            try_to_cast(x)
        else:
            try:
                lst[i] = float(x)
                lst[i] = int(x)
            except ValueError:
                pass

>>> try_to_cast(lst)
>>> print(lst)
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]

1) As pointed out in comments, your string is already valid YAML and thus can just be parsed with the yaml module without any pre- or postprocessing.

Upvotes: 1

Nordle
Nordle

Reputation: 3001

Here's a one liner utilizing split, strip and list comprehension;

string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
splitter = [x.split(',') for x in string.strip('[]').split('],[')]
print(splitter)

>>>[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']]

Although as mentioned it doesn't capture the float/int, they return as strings.

Upvotes: 0

Related Questions