0

给定一系列数字,我需要构建一个完整的“数字范围”集。我从一个列表开始,例如:

ID   START  
*    0  
a    4  
b    70  
c    700  
d    701  
e    85  
  • 其中“def”是默认范围&应该“填补”空白
  • “重叠”是起始数据中的值(70、700、701)

并需要以下结果:

ID  START  END  
*     0 - 39  
a     4 - 49  
*     5 - 69  
c   700 - 7009  
d   701 - 7019  
b   702 - 709  
*    71 - 849  
e    85 - 859  
*    86 - 9  

我想弄清楚的是是否有某种算法或设计模式来解决这个问题。我有一些想法,但我想我会先由“专家”来运行它。我正在使用 Python。

任何想法/方向将不胜感激。我有一些初步的想法:

  • 建立一个“范围”列表,将开始和结束值填充到全长。所以默认是 0000 到 9999
  • 构建动态构建的“拆分”列表
  • 循环遍历“范围”列表,将每个值与拆分列表中的值进行比较。
  • 如果发现重叠,请删除拆分列表中的值并添加新范围。
4

1 回答 1

0
import operator

ranges = {
    '4'  : 'a',
    '70' : 'b',
    '700': 'c',
    '701': 'd',
    '85' : 'e',
    '87' : 'a',
}

def id_for_value(value):
    possible = '*'
    for idvalue, id in sorted(ranges.iteritems()):
        if value.startswith(idvalue):
            possible = id
        elif idvalue > value:
            break
    return possible

知道某个值的id就足够了。测试:

assert id_for_value('10') == '*'
assert id_for_value('499') == 'a'
assert id_for_value('703') == 'b'
assert id_for_value('7007') == 'c'
assert id_for_value('7017') == 'd'
assert id_for_value('76') == id_for_value('83') == '*'
assert id_for_value('857') == 'e'
assert id_for_value('8716') == 'a'

如果你真的想要范围,你可以使用 itertools.groupby 来计算它:

def firstlast(iterator):
    """ Returns the first and last value of an iterator"""
    first = last = iterator.next()
    for value in iterator:
        last = value
    return first, last

maxlen = max(len(x) for x in ranges) + 1
test_range = ('%0*d' % (maxlen, i) for i in xrange(10 ** maxlen))
result = dict((firstlast(gr), id) 
              for id, gr in itertools.groupby(test_range, key=id_for_value))

给出:

{('0000', '3999'): '*',
 ('4000', '4999'): 'a',
 ('5000', '6999'): '*',
 ('7000', '7009'): 'c',
 ('7010', '7019'): 'd',
 ('7020', '7099'): 'b',
 ('7100', '8499'): '*',
 ('8500', '8599'): 'e',
 ('8600', '8699'): '*',
 ('8700', '8799'): 'a',
 ('8800', '9999'): '*'}
于 2009-02-19T19:05:03.313 回答