我正在寻找一种有效地表示一组索引的字符串格式。例如,"1-3,6,8-10,16“将产生1,2,3,6,8,9,10,16
理想情况下,我还可以表示无限序列。
有没有一种现有的标准方法来做到这一点?或者是一个好的库?或者你能提出你自己的格式吗?
谢谢!
编辑:哇!-感谢所有经过深思熟虑的回复。我同意我应该用“:”来代替。对无限列表有什么想法吗?我在考虑用"1..“来表示所有的正数。
这个用例是购物车。对于一些产品,我需要将产品销售限制为X的倍数,对于其他产品,我需要将产品销售限制为任何正数。因此,我正在寻找一种字符串格式来在数据库中表示它。
发布于 2009-09-26 13:48:36
如果您对Python语言感兴趣,我认为1:3,6,8:10,16将是更好的选择,因为x:y是索引范围的标准表示法,其语法允许您在对象上使用此表示法。请注意,调用
z[1:3,6,8:10,16]被翻译成
z.__getitem__((slice(1, 3, None), 6, slice(8, 10, None), 16))即使这是一个TypeError,如果z是一个内置容器,你也可以自由地创建返回一些合理的东西的类,例如NumPy的数组。
您可能还会说,按照惯例,5:和:5表示无限的索引范围(这有点夸张,因为Python没有带负索引或无限大正索引的内置类型)。
这里是解析器(一个漂亮的一行程序,下面描述了它的slice(16, None, None)故障):
def parse(s):
return [slice(*map(int, x.split(':'))) for x in s.split(',')]然而,有一个陷阱:根据定义,8:10只包括索引8和9 --没有上限。如果这对您的目的来说是不可接受的,那么您肯定需要一种不同的格式,而1-3,6,8-10,16在我看来很不错。然后,解析器将是
def myslice(start, stop=None, step=None):
return slice(start, (stop if stop is not None else start) + 1, step)
def parse(s):
return [myslice(*map(int, x.split('-'))) for x in s.split(',')]更新:以下是组合格式的完整解析器:
from sys import maxsize as INF
def indices(s: 'string with indices list') -> 'indices generator':
for x in s.split(','):
splitter = ':' if (':' in x) or (x[0] == '-') else '-'
ix = x.split(splitter)
start = int(ix[0]) if ix[0] is not '' else -INF
if len(ix) == 1:
stop = start + 1
else:
stop = int(ix[1]) if ix[1] is not '' else INF
step = int(ix[2]) if len(ix) > 2 else 1
for y in range(start, stop + (splitter == '-'), step):
yield y这也可以处理负数,所以
print(list(indices('-5, 1:3, 6, 8:15:2, 20-25, 18')))打印
[-5, 1, 2, 6, 7, 8, 10, 12, 14, 20, 21, 22, 23, 24, 25, 18, 19]还有另一种选择是使用... ( Python将其识别为内置常量省略号,因此如果愿意,您可以调用z[...] ),但我认为1,...,3,6, 8,...,10,16的可读性较差。
发布于 2009-09-26 14:00:28
你不需要一个字符串,这是最简单的方法:
from types import SliceType
class sequence(object):
def __getitem__(self, item):
for a in item:
if isinstance(a, SliceType):
i = a.start
step = a.step if a.step else 1
while True:
if a.stop and i > a.stop:
break
yield i
i += step
else:
yield a
print list(sequence()[1:3,6,8:10,16])输出:
[1, 2, 3, 6, 8, 9, 10, 16]我使用Python切片类型power来表示序列范围。我还使用生成器来提高内存效率。
请注意,我正在向切片停止添加1,否则范围将不同,因为切片中的停止不包括在内。
它支持以下步骤:
>>> list(sequence()[1:3,6,8:20:2])
[1, 2, 3, 6, 8, 10, 12, 14, 16, 18, 20]和无限序列:
sequence()[1:3,6,8:]
1, 2, 3, 6, 8, 9, 10, ...如果你必须给它一个字符串,那么你可以把@ilya N.parser和这个解决方案结合起来。我将扩展@ilya N.parser以支持索引和范围:
def parser(input):
ranges = [a.split('-') for a in input.split(',')]
return [slice(*map(int, a)) if len(a) > 1 else int(a[0]) for a in ranges]现在您可以像这样使用它:
>>> print list(sequence()[parser('1-3,6,8-10,16')])
[1, 2, 3, 6, 8, 9, 10, 16]发布于 2009-09-26 13:48:39
这可能是尽可能的懒惰,这意味着即使是非常大的列表也可以:
def makerange(s):
for nums in s.split(","): # whole list comma-delimited
range_ = nums.split("-") # number might have a dash - if not, no big deal
start = int(range_[0])
for i in xrange(start, start + 1 if len(range_) == 1 else int(range_[1]) + 1):
yield i
s = "1-3,6,8-10,16"
print list(makerange(s))输出:
[1, 2, 3, 6, 8, 9, 10, 16]https://stackoverflow.com/questions/1481192
复制相似问题