robertspierre
robertspierre

Reputation: 4351

Multiple split on strings

I have a string of the form:

s = "1,2;3,4"

I have to obtain:

res = [(1,2),(3,4)]

I could not came up better than:

pairs = [pair.split(",") for pair in s.split(";")]
res = [(int(a), int(b)) for a,b in pairs]

In fact this doesn't work:

>>> res = [(int(a),int(b)) for pair in s.split(";") for a,b in pair.split(",")]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
ValueError: not enough values to unpack (expected 2, got 1)

My questions are:

  1. Is there a one-liner solution? What's the most pythonic way to achieve this?
  2. Why my latter code doesn't work?

Upvotes: 2

Views: 106

Answers (3)

no comment
no comment

Reputation: 10153

Your attempt was almost correct, just need to wrap the pair split in an iterable:

change
[(int(a),int(b)) for pair in s.split(";") for a,b in pair.split(",")]

to:
[(int(a),int(b)) for pair in s.split(";") for a,b in [pair.split(",")]]

Short alternative:

[*map(eval, s.split(';'))]

(Use ast.literal_eval if the data can't be trusted.)

Upvotes: 0

U13-Forward
U13-Forward

Reputation: 71570

Try this instead:

>>> [tuple(int(x) for x in i.split(',')) for i in s.split(';')]
[(1, 2), (3, 4)]

Or with unpacking:

>>> [(*(int(x) for x in i.split(',')),) for i in s.split(';')]
[(1, 2), (3, 4)]
>>> 

Or:

>>> [tuple(map(int, i.split(','))) for i in s.split(';')]
[(1, 2), (3, 4)] 

You could try a list comprehension with tuple(map(...)) or a nested list comprehension.

The reason your code doesn't work is because you're trying to iterate through a list with two items while you're unpacking it by two iterators. Iteration isn't required for that. To fix your code try:

res = [(int(pair.split(',')[0]), int(pair.split(',')[1])) for pair in s.split(";")]
print(res)

Output:

[(1, 2), (3, 4)] 

Or:

[(int(a), int(b)) for a, b in [pair.split(",") for pair in s.split(";")]]

Upvotes: 3

user2390182
user2390182

Reputation: 73450

You can fix your own approach:

[(int(a), int(b)) for a, b in (pair.split(",") for pair in s.split(";"))]

Or you can be more concise, using some mapping and unpacking:

[(*map(int, p.split(",")),) for p in s.split(";")]
# [(1, 2), (3, 4)]

Upvotes: 0

Related Questions