索引的pythonic格式


问题内容

我追求的是字符串格式,以高效地表示一组索引。例如,“ 1-3,6,8-10,16”将产生[1,2,3,6,8,9,10,16]

理想情况下,我也能够表示无限序列。

是否有执行此操作的现有标准方法?还是好的图书馆?还是可以提出自己的格式?

谢谢!

编辑:哇!-感谢所有经过深思熟虑的回应。我同意我应该使用’:’代替。关于无限列表有什么想法吗?我当时正在考虑使用“ 1 ..”代表所有正数。

该用例用于购物车。对于某些产品,我需要将产品销量限制为X的倍数,而对于其他产品,则必须为正数。因此,我需要一种字符串格式来表示数据库中的该格式。


问题答案:

如果您喜欢Pythonic,我认为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))

即使这是一个TypeErrorifz内置容器,您也可以自由创建将返回合理值的类,例如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将其识别为内置常数Ellipsis,因此您可以z[...]根据需要调用它),但我认为1,...,3,6, 8,...,10,16它的可读性较差。