list comprehension for splitting strings into pairs

S

Steven Bethard

Here's what I'm doing:
lst = ['1', '1:2', '3', '-1:4']
splits = []
for s in lst:
.... pair = s.split(':')
.... if len(pair) != 2:
.... pair.append(None)
.... splits.append(pair)
.... [['1', None], ['1', '2'], ['3', None], ['-1', '4']]

Basically, I want to split each string into two items, substituting
None when no second item is specified in the string. (As you can see,
in my strings, the items are delimited by ':').

It seems like a simple enough operation that I should be able to write
a list comprehension for it, but I can't figure out how... Any
suggestions?

Steve
 
R

Russell Blau

Steven Bethard said:
Here's what I'm doing:
lst = ['1', '1:2', '3', '-1:4']
splits = []
for s in lst:
... pair = s.split(':')
... if len(pair) != 2:
... pair.append(None)
... splits.append(pair)
...[['1', None], ['1', '2'], ['3', None], ['-1', '4']]

Basically, I want to split each string into two items, substituting
None when no second item is specified in the string. (As you can see,
in my strings, the items are delimited by ':').

It seems like a simple enough operation that I should be able to write
a list comprehension for it, but I can't figure out how... Any
suggestions?

How's this?
lst = ['1', '1:2', '3', '-1:4']
splits = [':' in item and item.split(':', 1) or [item, None] \ for item in lst]
splits
[['1', None], ['1', '2'], ['3', None], ['-1', '4']]

This approach is cute, but lacks any error-checking, so you can only use it
if you are fairly sure your "lst" will contain strings in the proper format.
 
B

Bob Follek

Here's what I'm doing:
lst = ['1', '1:2', '3', '-1:4']
splits = []
for s in lst:
... pair = s.split(':')
... if len(pair) != 2:
... pair.append(None)
... splits.append(pair)
... [['1', None], ['1', '2'], ['3', None], ['-1', '4']]

Basically, I want to split each string into two items, substituting
None when no second item is specified in the string. (As you can see,
in my strings, the items are delimited by ':').

It seems like a simple enough operation that I should be able to write
a list comprehension for it, but I can't figure out how... Any
suggestions?

Steve

Here's a pretty nasty approach:
lst = ['1', '1:2', '3', '-1:4']
splits = [(e.split(':') + [None])[:2] for e in lst]
splits
[['1', None], ['1', '2'], ['3', None], ['-1', '4']]
 
S

Steven Bethard

Russell Blau said:
lst = ['1', '1:2', '3', '-1:4']
splits = [':' in item and item.split(':', 1) or [item, None] for item in lst]
splits
[['1', None], ['1', '2'], ['3', None], ['-1', '4']]

Oooh. Pretty. =)

What if I want to convert my splits list to:

[[1, None], [1, 2], [3, None], [-1, 4]]

where I actually call int on each of the non-None items? Obviously I could
extend your example to:
lst = ['1', '1:2', '3', '-1:4']
splits = [':' in item and [int(x) for x in item.split(':', 1)]
.... or [int(item), None]
.... for item in lst][[1, None], [1, 2], [3, None], [-1, 4]]

But that's getting to be a bit more work than looks good to me in a list
comprehension. I thought about doing it in two steps:
splits = [':' in item and item.split(':', 1) or [item, None] .... for item in lst]
splits = [[int(i), p is not None and int(p) or p] .... for i, p in splits]
splits
[[1, None], [1, 2], [3, None], [-1, 4]]

This looks decent to me, but if you see a better way, I'd love to hear about
it. =)

Thanks again!

Steve
 
S

Steven Bethard

Steven Bethard said:
splits = [':' in item and item.split(':', 1) or [item, None] ... for item in lst]
splits = [[int(i), p is not None and int(p) or p] ... for i, p in splits]
splits
[[1, None], [1, 2], [3, None], [-1, 4]]

So I realized that this doesn't quite work if the second item in a split is 0 -
- you'll end up with None instead of 0.

Steve
 
M

Martin Maney

Steven Bethard said:
lst = ['1', '1:2', '3', '-1:4']
splits = []
for s in lst:
.... pair = s.split(':')
.... if len(pair) != 2:
.... pair.append(None)
.... splits.append(pair)
.... [['1', None], ['1', '2'], ['3', None], ['-1', '4']]
Basically, I want to split each string into two items, substituting
None when no second item is specified in the string. (As you can see,
in my strings, the items are delimited by ':').
Ah!
lst = ['1', '1:2', '3', '-1:4']
[ (x.split(':') + [None])[:2] for x in lst]
[['1', None], ['1', '2'], ['3', None], ['-1', '4']]

Handles both single-element and more-than-two-element strings. Doesn't
crash on empty strings, but the result probably isn't useful:
[ (x.split(':') + [None])[:2] for x in ['1', '1:2', '3', '-1:4', '']]
[['1', None], ['1', '2'], ['3', None], ['-1', '4'], ['', None]]

You might also enjoy this variation
[ (map(int, x.split(':')) + [None])[:2] for x in lst]
[[1, None], [1, 2], [3, None], [-1, 4]]

Since I saw you mention wanting that later, I think. Didn't see any
replies quite the same as this (but I didn't troll through the rest of
the spool looking for possible unthreaded replies).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,141
Latest member
BlissKeto
Top