Home > Enterprise >  How to transform a string into a list of char and int using a list comprehension in Python
How to transform a string into a list of char and int using a list comprehension in Python

Time:02-12

Given the following string:

"[10,20]"

I want to create the following list using a list comprehension in Python:

['[', 10, ',', 20, ']']

Being 10 and 20 integers and the rest of the elements in the list chars.

I assume that I would need a to use something similar to what itertools.groupby(iterable, key=None) provides:

Make an iterator that returns consecutive keys and groups from the iterable. The key is a function computing a key value for each element. If not specified or is None, key defaults to an identity function and returns the element unchanged. Generally, the iterable needs to already be sorted on the same key function.

However Python's group by returns an iterator with consecutive keys and groups. In my case the keys would change so I guess I'd need a similar iterator that returns the groups based on a filter. Any ideas?

CodePudding user response:

Group by whether this character is numeric or not. This can be done using the str.isnumeric function as the key argument to groupby().

s = "[10,20]"
g = itertools.groupby(s, key=str.isnumeric)

Then, for the True groups, convert it to an integer. Leave False groups as-is. Since the values of the groupby are iterators where each element is a separate character, you need to join it with "" to convert it into a single string, and optionally convert that string to an integer.

lst = [int("".join(chars)) if is_numeric else "".join(chars) for is_numeric, chars in g]

Which gives:

['[', 10, ',', 20, ']']

In one line:

lst = [                  int("".join(chars)) 
      if is_numeric else "".join(chars) 
      for is_numeric, chars in itertools.groupby(s, key=str.isnumeric)
      ]

CodePudding user response:

This can also be done with regex with ease.

import re

NUMCHR = re.compile(r'\d |[^\d]') #consecutive digits OR one "not-a-digit"
data   = '[10,20]'
out    = [int(m[0]) if m[0].isdigit() else m[0] for m in NUMCHR.finditer(data)]

print(out) #['[', 10, ',', 20, ']']

.finditer (in this case) will return either consecutive numbers or only 1 character on each iteration. We just check the return and proceed accordingly.

CodePudding user response:

Use str.isdigit as your grouping key and convert groups that have a key of True to integers:

from itertools import groupby

s = "[10,20]"

r = [[str,int][k]("".join(g)) for k,g in groupby(s,key=str.isdigit)]

print(r)
['[', 10, ',', 20, ']']

CodePudding user response:

You could also use reduce from functools:

from functools import reduce
def fun(x, y):
    if isinstance(x[-1], str) and x[-1].isdigit():
        x[-1] = x[-1]   y if y.isdigit()  else int(x[-1])
    else:
        x  = [y]      
    return x

reduce(fun, '[10,[20,30]]', [''])[1:]
Out[]: ['[', 10, '[', 20, 30, ']']

Another approach may be to use recursion:

def fun_recurse(y, x=None):     
    if x is None:
        x = ['']
    if len(y) == 1:
        return x[1:]   [y]
    if isinstance(x[-1], str) and x[-1].isdigit():
       x[-1] = x[-1]   y[0] if y[0].isdigit() else int(x[-1])
       return fun_recurse(y[1:], x)
    else:
        return fun_recurse(y[1:], x   [y[0]])

fun_recurse('[10,[20,30]]')
Out[]: ['[', 10, '[', 20, 30, ']']
  • Related