在python中从数字列表打印格式化的数字范围字符串

在python中从数字列表打印格式化的数字范围字符串,python,Python,我编写这个类是为了将数字列表压缩并扩展为序列字符串,包括步长值大于1时的步长值。代码仍然感觉笨拙。有这样的图书馆吗?可能更简单的代码 import re class Foo( object ): def __init__( self, num_list ): self.num_list = sorted( list( set( [ int(n) for n in num_list ] ) ) ) # end def __init__ def gen_

我编写这个类是为了将数字列表压缩并扩展为序列字符串,包括步长值大于1时的步长值。代码仍然感觉笨拙。有这样的图书馆吗?可能更简单的代码

import re

class Foo( object ):

    def __init__( self, num_list ):
        self.num_list = sorted( list( set( [ int(n) for n in num_list ] ) ) )
    # end def __init__

    def gen_seq_data( self ):
        self.seq_data       = list()
        index_offset        = None
        backward_step_value = None
        forward_step_value  = None
        sub_list            = list()
        sub_list_step_value = None
        for index, num in enumerate( self.num_list ):

            if index - 1 < 0:
                backward_step_value = None
            # end if
            else:
                backward_step_value = num - self.num_list[ index - 1 ]
            # end else

            try:
                forward_step_value = self.num_list[ index + 1 ] - num
            # end try
            except IndexError:
                forward_step_value = None
            # end except

            if backward_step_value is None:
                sub_list.append( num )
            # end if
            elif backward_step_value == forward_step_value:
                sub_list.append( num )
                if forward_step_value is None:
                    self.seq_data.append( ( sub_list_step_value, sub_list ) )
                # end if
            # end if
            elif backward_step_value == sub_list_step_value:
                sub_list.append( num )
                if sub_list:
                    self.seq_data.append( ( sub_list_step_value, sub_list ) )
                # end if
                sub_list = list()
            # end elif
            else:
                if sub_list:
                    self.seq_data.append( ( sub_list_step_value, sub_list ) )
                # end if
                sub_list = [ num ]
                if forward_step_value is None:
                    self.seq_data.append( ( sub_list_step_value, sub_list ) )
                # end if
            # end else

            try:
                sub_list_step_value = sub_list[ -1 ] - sub_list[ -2 ]
            # end try
            except IndexError:
                sub_list_step_value = None
            # end except
        # end for
    # end def gen_seq_object

    def format_elements( self ):
        format_elements = list()
        for step, num_list in self.seq_data:
            if step is None:
                format_elements.append( '%s' % ( num_list[ 0 ] ) )
            # end if
            elif step == 1:
                format_elements.append( '%s-%s' % ( num_list[ 0 ], num_list[ -1 ] ) )
            # end elif
            else:
                format_elements.append( '%s-%sx%s' % ( num_list[ 0 ], num_list[ -1 ], step ) )
            # end else
        # end for
        return format_elements
    # end def format_range

    def format_range( self ):
       return ','.join( self.format_elements() )
    # end def format_range

    def expand_range( self ):
        num_list = list()
        for r_token in self.format_range().split( ',' ):
            if r_token.isdigit():
                num_list.append( int( r_token ) )
            # end if
            elif '-' in r_token:
                if 'x' in r_token:
                    start, end, step = re.split( r'[-|x]', r_token )
                    num_list.extend( range( int( start ), int( end ) + 1, int( step ) ) )
                # end if
                else:
                    start, end = r_token.split( '-' )
                    num_list.extend( range( int( start ), int( end ) + 1 ) )
                # end else
           # end elif
        # end for
        return num_list
    # end def expand_range

# end class Foo
一个。删除所有结束评论。它们毫无用处。你的缩进说明了一切。使用它

两个。不要把这当成一门课。它不是一个具有不同责任的不同对象。这只是一个算法。由函数组成。充其量它是一个包含所有静态方法的类

三个。永远不要这样做

    for index, num in enumerate( self.num_list ):
        if index - 1 < 0:
            backward_step_value = None
        # end if
        else:
            backward_step_value = num - self.num_list[ index - 1 ]
        # end else
像这样的东西很少需要索引。事实上,拥有索引的唯一原因似乎是专门处理第一个元素

最后,这是一种“减少”。使用生成器函数

def reduce_list( some_list ):
    v= min(some_list)
    low, high = v, v
    for v in sorted(some_list)[1:]:
        if v == high+1: 
            high= high+1
        else:
            yield low, high
     yield low, high
这可能会生成连续范围的列表。然后可以格式化这些文件

format_elements( reduce_list( some_list ) )

以下解决方案处理非连续范围,并保留忽略长度为2的范围的行为

def reduce_list(seq):
    l = sorted(set(seq))
    low = high = l[0]
    step = None
    for v in l[1:]:
        if step is None or v - high == step:
            # Extend the current range.
            step = v - high
            high = v
        elif high - low == step:
            # The current range only has two values.  Yield the
            # first value, and start a new range comprising the
            # second value and the current value.
            yield low, low, None
            step = v - high
            low = high
            high = v
        else:
            # Yield the current range, and start a new one.
            yield low, high, step
            low = high = v
            step = None
    if high - low == step:
        # The final range has only two values.  Yield them
        # individually.
        yield low, low, None
        step = None
        low = high
    yield low, high, step

def format_element(low, high, step):
    if step is None:
        assert low == high
        return "%s" % (low,)
    elif step == 1:
        return "%s-%s" % (low, high)
    else:
        return "%s-%sx%s" % (low, high, step)

def format_list(seq):
    return ','.join(format_element(*e) for e in seq)
下面是一些测试代码:

def test( *args ):
    print args, "==", format_list(reduce_list(args))

test(1)
test(1, 2)
test(1, 2, 3)
test(0, 10)
test(0, 10, 20)
test(0, 10, 11, 12, 14, 16)
test(0, 2, 4, 8, 16, 32, 64)
test(0, 1, 3, 4, 6, 7, 9, 10)
test(0, 1, 3, 6, 10, 15, 21, 28)
哪些产出:

(1,) == 1
(1, 2) == 1,2
(1, 2, 3) == 1-3
(0, 10) == 0,10
(0, 10, 20) == 0-20x10
(0, 10, 11, 12, 14, 16) == 0,10-12,14,16
(0, 2, 4, 8, 16, 32, 64) == 0-4x2,8,16,32,64
(0, 1, 3, 4, 6, 7, 9, 10) == 0,1,3,4,6,7,9,10
(0, 1, 3, 6, 10, 15, 21, 28) == 0,1,3,6,10,15,21,28

请修正你的缩进。您的代码格式不正确。请(1)编辑问题,(2)阅读页面右侧的格式说明,(3)避免发布您拥有的每一段代码。你有什么问题?显示此问题的最小代码是什么?@user494203:扔掉“#end if”等行;它们毫无用处,尤其是在
elif
else
之前发生的那些。如果您这样做,人们可能会更倾向于阅读您的代码并建议进一步的清除。此解决方案无法实现OP解决方案中最棘手的部分,即不仅识别连续范围,而且识别固定步长大于1的范围。@jchl:正确。重点不是修复他们的代码。重点是提供一种方法来修改代码,使其不那么“笨重”。将步骤作为变量而不是
1
作为扩展应该不会太难。谢谢您的帮助。这些都是很好的解决方案。
def test( *args ):
    print args, "==", format_list(reduce_list(args))

test(1)
test(1, 2)
test(1, 2, 3)
test(0, 10)
test(0, 10, 20)
test(0, 10, 11, 12, 14, 16)
test(0, 2, 4, 8, 16, 32, 64)
test(0, 1, 3, 4, 6, 7, 9, 10)
test(0, 1, 3, 6, 10, 15, 21, 28)
(1,) == 1
(1, 2) == 1,2
(1, 2, 3) == 1-3
(0, 10) == 0,10
(0, 10, 20) == 0-20x10
(0, 10, 11, 12, 14, 16) == 0,10-12,14,16
(0, 2, 4, 8, 16, 32, 64) == 0-4x2,8,16,32,64
(0, 1, 3, 4, 6, 7, 9, 10) == 0,1,3,4,6,7,9,10
(0, 1, 3, 6, 10, 15, 21, 28) == 0,1,3,6,10,15,21,28