索引的pythonic格式

hoj*_*oju 6 python indexing set sequence

我正在使用字符串格式来有效地表示一组索引.例如"1-3,6,8-10,16"会产生[1,2,3,6,8,9,10,16]

理想情况下,我也能够代表无限的序列.

是否有现成的标准方法?还是一个好的图书馆?或者你可以提出自己的格式吗?

谢谢!

编辑:哇! - 感谢所有考虑周全的回复.我同意我应该使用':'代替.关于无限列表的任何想法?我想用"1 .."代表所有正数.

用例是购物车.对于某些产品,我需要将产品销售限制为X的倍数,对于其他产品,我要将其限制为正数.所以我追求一种字符串格式来代表数据库.

Nad*_*mli 7

你不需要一个字符串,这很简单:

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])
Run Code Online (Sandbox Code Playgroud)

输出:

[1, 2, 3, 6, 8, 9, 10, 16]
Run Code Online (Sandbox Code Playgroud)

我正在使用Python切片类型的功能来表达序列范围.我也使用生成器来提高内存效率.

请注意,我在切片停止处添加1,否则范围将不同,因为切片中的停止不包括在内.

它支持以下步骤:

>>> list(sequence()[1:3,6,8:20:2])
[1, 2, 3, 6, 8, 10, 12, 14, 16, 18, 20]
Run Code Online (Sandbox Code Playgroud)

无限的序列:

sequence()[1:3,6,8:]
1, 2, 3, 6, 8, 9, 10, ...
Run Code Online (Sandbox Code Playgroud)

如果你必须给它一个字符串,那么你可以组合@ilya n.使用此解决方案解析器.我会延长@ilya n.解析器以支持索引和范围:

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]
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样使用它:

>>> print list(sequence()[parser('1-3,6,8-10,16')])
[1, 2, 3, 6, 8, 9, 10, 16]
Run Code Online (Sandbox Code Playgroud)


ily*_* n. 3

如果您喜欢Pythonic,我认为这1:3,6,8:10,16将是一个更好的选择,因为x:y索引范围的标准表示法和语法允许您在对象上使用此表示法。请注意,调用

z[1:3,6,8:10,16]
Run Code Online (Sandbox Code Playgroud)

被翻译成

z.__getitem__((slice(1, 3, None), 6, slice(8, 10, None), 16))
Run Code Online (Sandbox Code Playgroud)

即使这是一个TypeErrorifz是内置容器,您也可以自由创建将返回合理内容的类,例如 NumPy 的数组。

您也可能会说,按照惯例5::5表示无限索引范围(这有点夸张,因为 Python 没有带有负索引或无限大正索引的内置类型)。

这是解析器(一个漂亮的单行代码,但存在slice(16, None, None)如下所述的故障):

def parse(s):
    return [slice(*map(int, x.split(':'))) for x in s.split(',')]
Run Code Online (Sandbox Code Playgroud)

然而,有一个陷阱: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(',')]
Run Code Online (Sandbox Code Playgroud)

更新:这是组合格式的完整解析器:

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
Run Code Online (Sandbox Code Playgroud)

这也处理负数,所以

 print(list(indices('-5, 1:3, 6, 8:15:2, 20-25, 18')))
Run Code Online (Sandbox Code Playgroud)

印刷

[-5, 1, 2, 6, 7, 8, 10, 12, 14, 20, 21, 22, 23, 24, 25, 18, 19]
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用...(Python 将其识别为内置常量省略号,因此您可以z[...]根据需要调用),但我认为1,...,3,6, 8,...,10,16可读性较差。