1

Assuming I have a path such as /resource/123/resourceb/b/someotherresource/. In this case someotherresource has no resource id. This example has 3 resources, but I need to handler anywhere between 1-4 resources.

What is a pythonic way to split it into [(a,b), (c,d), (e, None)]

Example:

x =  '/resource/123/resourceb/b/someotherresource/'
xplit = x.split('/')
>>> [ 'resource', '123', 'resourceb', 'b', 'someotherresource']
import magic
# ideal result
>>> [ ('resource', '123'), ('resourceb', 'b'), ('someotherresource', None)]

I know I can do it the stupid way, but is there a simple way to split & pair an array of odd length ?

Nix
  • 57,072
  • 29
  • 149
  • 198
  • Would adapting [this answer](http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python) to handle odd numbers do the trick, or is that the stupid way of which you speak. – cms_mgr Feb 04 '13 at 17:47
  • @cms_mgr The top answer to that question is sub-optimal as it only works on sequences, not arbitrary iterables. – Gareth Latty Feb 04 '13 at 17:49

3 Answers3

2

Use itertools.izip_longest() and iter magic:

import itertools
list(itertools.izip_longest(*[iter(xplit[1:])]*2))

We start at index 1 because the leading / slash gives you an empty element at the start.

Alternatively, strip of the slashes at start and end:

list(itertools.izip_longest(*[iter(x.strip('/').split('/'))]*2))

Output:

>>> list(itertools.izip_longest(*[iter(x.strip('/').split('/'))]*2))
[('resource', '123'), ('resourceb', 'b'), ('someotherresource', None)]

Wrapped up as magic method:

import itertools

def split_to_pairs(path):
    path = path.strip('/').split('/')
    return list(itertools.izip_longest(*[iter(path)]*2))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2
In [24]: x
Out[24]: '/resource/123/resourceb/b/someotherresource/'

In [25]: s = x.strip('/').split('/')

In [26]: zip(s[::2], s[1::2] + [None])
Out[26]: [('resource', '123'), ('resourceb', 'b'), ('someotherresource', None)]
Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
  • 1
    +1 I like this one. No strings attached, no dependencies. No lambdas. Just striding slices and zip. Nice – sehe Feb 04 '13 at 17:55
  • This does rely on `s` being a list, instead of an arbitrary iterable, which is a little sub-optimal depending on usage. (It also wouldn't scale well to different sized groups). – Gareth Latty Feb 04 '13 at 17:56
1

Check out the grouper() recipie from itertools:

def grouper(n, iterable, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

(In 2.x, zip_longest() is izip_longest())

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183