Cómo convertir rangos de cadenas numéricas a una lista en Python

Me gustaría poder convertir una cadena como “1,2,5-7,10” a una lista de python como [1,2,5,6,7,10]. Miré a mi alrededor y encontré esto , pero me preguntaba si hay una forma limpia y sencilla de hacerlo en Python.

>>> def f(x): ... result = [] ... for part in x.split(','): ... if '-' in part: ... a, b = part.split('-') ... a, b = int(a), int(b) ... result.extend(range(a, b + 1)) ... else: ... a = int(part) ... result.append(a) ... return result ... >>> f('1,2,5-7,10') [1, 2, 5, 6, 7, 10] 

Pude hacer una verdadera comprensión de esa pregunta:

 >>> def f(s): return sum(((list(range(*[int(j) + k for k,j in enumerate(i.split('-'))])) if '-' in i else [int(i)]) for i in s.split(',')), []) >>> f('1,2,5-7,10') [1, 2, 5, 6, 7, 10] >>> f('1,3-7,10,11-15') [1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] 

La otra respuesta que pretendía tener una comprensión era solo un bucle for porque la lista final se descartó. 🙂

¡Para Python 2 puedes incluso eliminar la llamada a la list !

Esto podría ser una exageración, pero me gusta pyparsing:

 from pyparsing import * def return_range(strg, loc, toks): if len(toks)==1: return int(toks[0]) else: return range(int(toks[0]), int(toks[1])+1) def parsestring(s): expr = Forward() term = (Word(nums) + Optional(Literal('-').suppress() + Word(nums))).setParseAction(return_range) expr << term + Optional(Literal(',').suppress() + expr) return expr.parseString(s, parseAll=True) if __name__=='__main__': print parsestring('1,2,5-7,10') 

¡Ugh, las respuestas son tan detalladas! Aquí hay una respuesta corta y elegante:

 def rangeString(commaString): def hyphenRange(hyphenString): x = [int(x) for x in hyphenString.split('-')] return range(x[0], x[-1]+1) return chain(*[hyphenRange(r) for r in commaString.split(',')]) 

Manifestación:

 >>> list( f('1,2,5-7,10') ) [1, 2, 5, 6, 7, 10] 

Fácilmente modificable para manejar números negativos o devolver una lista. También necesitará la from itertools import chain , pero puede sustituirla por sum(...,[]) si no está trabajando con objetos de range (o sum(map(list,iters),[]) ) y no lo hace ‘ No te preocupes por ser perezoso.

¡Ninguna comprensión supera la mía!

 import re def convert(x): return sum((i if len(i) == 1 else list(range(i[0], i[1]+1)) for i in ([int(j) for j in i if j] for i in re.findall('(\d+),?(?:-(\d+))?', x))), []) 

La mejor parte es que uso la variable i dos veces en medio de la comprensión.

 >>> convert('1,2,5-7,10') [1, 2, 5, 6, 7, 10] 

Muy corto, y elegante (imho):

 >>> txt = "1,2,5-7,10" >>> # construct list of xranges >>> xranges = [(lambda l: xrange(l[0], l[-1]+1))(map(int, r.split('-'))) for r in txt.split(',')] >>> # flatten list of xranges >>> [y for x in xranges for y in x] [1, 2, 5, 6, 7, 10]