首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >pythonic索引格式

pythonic索引格式
EN

Stack Overflow用户
提问于 2009-09-26 13:21:53
回答 5查看 282关注 0票数 6

我正在寻找一种有效地表示一组索引的字符串格式。例如,"1-3,6,8-10,16“将产生1,2,3,6,8,9,10,16

理想情况下,我还可以表示无限序列。

有没有一种现有的标准方法来做到这一点?或者是一个好的库?或者你能提出你自己的格式吗?

谢谢!

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

这个用例是购物车。对于一些产品,我需要将产品销售限制为X的倍数,对于其他产品,我需要将产品销售限制为任何正数。因此,我正在寻找一种字符串格式来在数据库中表示它。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-09-26 13:48:36

如果您对Python语言感兴趣,我认为1:3,6,8:10,16将是更好的选择,因为x:y是索引范围的标准表示法,其语法允许您在对象上使用此表示法。请注意,调用

代码语言:javascript
复制
z[1:3,6,8:10,16]

被翻译成

代码语言:javascript
复制
z.__getitem__((slice(1, 3, None), 6, slice(8, 10, None), 16))

即使这是一个TypeError,如果z是一个内置容器,你也可以自由地创建返回一些合理的东西的类,例如NumPy的数组。

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

这里是解析器(一个漂亮的一行程序,下面描述了它的slice(16, None, None)故障):

代码语言:javascript
复制
def parse(s):
    return [slice(*map(int, x.split(':'))) for x in s.split(',')]

然而,有一个陷阱:根据定义,8:10只包括索引8和9 --没有上限。如果这对您的目的来说是不可接受的,那么您肯定需要一种不同的格式,而1-3,6,8-10,16在我看来很不错。然后,解析器将是

代码语言:javascript
复制
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(',')]

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

代码语言:javascript
复制
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

这也可以处理负数,所以

代码语言:javascript
复制
 print(list(indices('-5, 1:3, 6, 8:15:2, 20-25, 18')))

打印

代码语言:javascript
复制
[-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的可读性较差。

票数 3
EN

Stack Overflow用户

发布于 2009-09-26 14:00:28

你不需要一个字符串,这是最简单的方法:

代码语言:javascript
复制
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])

输出:

代码语言:javascript
复制
[1, 2, 3, 6, 8, 9, 10, 16]

我使用Python切片类型power来表示序列范围。我还使用生成器来提高内存效率。

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

它支持以下步骤:

代码语言:javascript
复制
>>> list(sequence()[1:3,6,8:20:2])
[1, 2, 3, 6, 8, 10, 12, 14, 16, 18, 20]

和无限序列:

代码语言:javascript
复制
sequence()[1:3,6,8:]
1, 2, 3, 6, 8, 9, 10, ...

如果你必须给它一个字符串,那么你可以把@ilya N.parser和这个解决方案结合起来。我将扩展@ilya N.parser以支持索引和范围:

代码语言:javascript
复制
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]

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

代码语言:javascript
复制
>>> print list(sequence()[parser('1-3,6,8-10,16')])
[1, 2, 3, 6, 8, 9, 10, 16]
票数 7
EN

Stack Overflow用户

发布于 2009-09-26 13:48:39

这可能是尽可能的懒惰,这意味着即使是非常大的列表也可以:

代码语言:javascript
复制
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))

输出:

代码语言:javascript
复制
[1, 2, 3, 6, 8, 9, 10, 16]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1481192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档