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]