Elegant way to split a list of strings into nested lists with values of type float
Question:
Looking for an elegant way to split/format the below list of strings:
ls = ["12,45 58,96",
"23,67 94,92 93,10",
"45,76 33,11 46,33"]
Goal is nested lists of [x, y] coordinates of type float:
goal = [[[12.0,45.0], [58.0,96.0]],
[[23.0,67.0], [94.0,92.0], [93.0,10.0]]
[[etc ......
I have solved this with the below code, but it’s rough (and embarrassing!) and I know there has to be a much more elegant way, maybe using list comprehensions or generators?
s = []
for i in ls:
i.split(' ')
s.append(i)
res = [i.split(' ') for i in s] # splits at the space
gen = (map(lambda n: n.split(','), x) for x in res) # split list elements at comma
result = (list(x) for x in gen)
final = []
for i in result: # convert each string to a float
sublist1 = []
for x in i:
sub = []
for z in x:
z = float(z)
sub.append(z)
sublist1.append(sub)
final.append(sublist1)
print(list(final))
Answers:
You can try list comprehension like this –
newlist = [[[float(v) for v in e.split(',')] for e in st.split()] for st in l]
Output:
[[[12.0, 45.0], [58.0, 96.0]], [[23.0, 67.0], [94.0, 92.0], [93.0, 10.0]], [[45.0, 76.0], [33.0, 11.0], [46.0, 33.0]]]
Using map
a = ["12,45 58,96", "23,67 94,92 93,10", "45,76 33,11 46,33"]
list(map(lambda x: list(map(lambda a: list(map(float, a.split(","))), x.split(" "))), a))
Honestly, there are so many ways to write this, and if it will look elegant or not, it will depend on what you understand by elegance.
If elegance is terseness and straightforwardness, you can do list comprehension:
[[[float(v) for v in c.split(',')] for c in l.split()] for l in ls]
If elegance is purity, you can write a fully "point-free" functional expression (even without lambdas), that look completely alien:
from functools import partial
list(map(list, map(partial(map, list), (map(partial(map, partial(map, float)), map(partial(map, partial(str.split, sep=',')), map(str.split, ls)))))))
Now, if elegance is clarity and maintainability, you do the most obvious and self documented code:
def as_coords(ls):
for string in ls:
arr = []
for coord in string.split():
x, y = coord.split(',')
arr.append([float(x), float(y)])
yield arr
list(as_coords(ls))
Looking for an elegant way to split/format the below list of strings:
ls = ["12,45 58,96",
"23,67 94,92 93,10",
"45,76 33,11 46,33"]
Goal is nested lists of [x, y] coordinates of type float:
goal = [[[12.0,45.0], [58.0,96.0]],
[[23.0,67.0], [94.0,92.0], [93.0,10.0]]
[[etc ......
I have solved this with the below code, but it’s rough (and embarrassing!) and I know there has to be a much more elegant way, maybe using list comprehensions or generators?
s = []
for i in ls:
i.split(' ')
s.append(i)
res = [i.split(' ') for i in s] # splits at the space
gen = (map(lambda n: n.split(','), x) for x in res) # split list elements at comma
result = (list(x) for x in gen)
final = []
for i in result: # convert each string to a float
sublist1 = []
for x in i:
sub = []
for z in x:
z = float(z)
sub.append(z)
sublist1.append(sub)
final.append(sublist1)
print(list(final))
You can try list comprehension like this –
newlist = [[[float(v) for v in e.split(',')] for e in st.split()] for st in l]
Output:
[[[12.0, 45.0], [58.0, 96.0]], [[23.0, 67.0], [94.0, 92.0], [93.0, 10.0]], [[45.0, 76.0], [33.0, 11.0], [46.0, 33.0]]]
Using map
a = ["12,45 58,96", "23,67 94,92 93,10", "45,76 33,11 46,33"]
list(map(lambda x: list(map(lambda a: list(map(float, a.split(","))), x.split(" "))), a))
Honestly, there are so many ways to write this, and if it will look elegant or not, it will depend on what you understand by elegance.
If elegance is terseness and straightforwardness, you can do list comprehension:
[[[float(v) for v in c.split(',')] for c in l.split()] for l in ls]
If elegance is purity, you can write a fully "point-free" functional expression (even without lambdas), that look completely alien:
from functools import partial
list(map(list, map(partial(map, list), (map(partial(map, partial(map, float)), map(partial(map, partial(str.split, sep=',')), map(str.split, ls)))))))
Now, if elegance is clarity and maintainability, you do the most obvious and self documented code:
def as_coords(ls):
for string in ls:
arr = []
for coord in string.split():
x, y = coord.split(',')
arr.append([float(x), float(y)])
yield arr
list(as_coords(ls))