2011-08-16 53 views
1

我正在尝试查找列表中数字是否为顺序的最pythonic方法。为了给出一些背景知识,我列出了一个存在于一个文件夹中的数字列表,并且我需要找出哪些数字缺失。确定列表中的序列号(Python)

我收集所有的数字,然后从范围(开始,结束+1)的数字应该在那里的另一个列表。我很容易做的东西给我看所有号码的丢失:

missing = [x for x in existingNumbers if x not in shouldBeNumbers] 

的问题是,如果我打印出所有这些,有很多的数字可能被凝结(即1,2,3 ,4,7,10可以打印为1-4,7,10),因为可能会丢失大量数字。

我已经试过两种方法:

对于这两种方式,frameRange是范围(startFrame将,endFrame + 1),页框是目前存在什么生成的列表。

1)

for x in frameRange: 
     if x not in frameList: 
      if originalFrame == None: 
       originalFrame = x 
      elif originalFrame: 
       if lastFrame == None: 
        lastFrame = x 
       elif lastFrame: 
        if lastFrame == x-1: 
         lastFrame = x 
        else: 
         if originalFrame != lastFrame: 
          missingFrames.append(str(originalFrame)+"-"+str(lastFrame)) 
          originalFrame = x 
          lastFrame = x 
         else: 
          missingFrames.append(str(originalFrame)) 
          originalFrame = x 
          lastFrame = x 
     if x == endFrame: 
      if originalFrame != lastFrame: 
       missingFrames.append(str(originalFrame)+"-"+str(lastFrame)) 
       originalFrame = x 
       lastFrame = x 
      else: 
       missingFrames.append(str(originalFrame)) 
       originalFrame = x 
       lastFrame = x 

2)

i = 0 
    while i < len(frameRange): 
     if frameRange[i] in frameList: 
      i += 1 
     else: 
      if i + 1 < len(frameRange): 
       if frameRange[i + 1] in frameList: 
        missingFrames.append(str(frameRange[i])) 
        i += 1 
       else: 
        j = 1 
        while frameRange[i+j] not in frameList: 
         aheadFrameNumber = int(str(j)) 
         if i + j + 1 < len(frameRange): 
          j += 1 
         else: 
          break 
        missingFrames.append(str(frameRange[i])+"-"+str(frameRange[aheadFrameNumber])) 
        if i + aheadFrameNumber + 1 < len(frameRange): 
         i += aheadFrameNumber + 1 
      else: 
       missingFrames.append(str(frameRange[i])) 

第一种方式是工作,但因为它发生在当前帧检查上次上,只要最后一帧不见了它不会将最后一个缺少的部分追加到列表中。对于第二种方法,我不得不一直将所有内容都包含在if语句中,因为在向前移动时我总是收到索引异常。

我想我必须退一步,重新思考,并以不同的方式来对待它。我想知道是否有更好的方法来做到这一点,我还没有想过,因为我不知道这个功能。两种方式开始有点失控。

+0

你能提供一个典型列表的示例你想通过?例如。它可以像'[1,3,4,5,6,3,10,12]'吗?或'[1,2,3,4,7,17​​,18,19,20]'。另外,基于给出的例子,期望的结果是什么? – dtlussier

+0

典型的列表是带有编号文件的文件夹。这些文件可能会成千上万,到目前为止最大的列表是13k(通常只有2k)。这些文件按照20个批次的顺序依次添加。因此,对于这种现有的列表可能是:[1,2,3,21,22,23,24],其中预期总数为1-100。这将输出'“MISSING:4-20,25-100”' 此外,我已经更新了我的原始帖子后,我离开了它一段时间后,我的解决方案。它有效,但如果你有任何建议,请告诉。谢谢。 – STH

回答

3

尝试这样的事情

missing=[] 
numbers.insert(0, 0) # add the minimum value on begining of the list 
numbers.append(41) # add the maximum value at the end of the list 
for rank in xrange(0, len(numbers)-1): 
    if numbers[rank+1] - numbers[rank] > 2: 
     missing.append("%s-%s"%(numbers[rank] +1 , numbers[rank+1] - 1)) 
    elif numbers[rank+1] - numbers[rank] == 2: 
     missing.append(str(numbers[rank]+1)) 

print missing 

这对于numbers = [1,4,6,10, 12,]和数字应该存在是从1到40,你将有:

['2-3', '5', '7-9', '11', '13-40'] 
+0

我看到这适用于场景,现有列表的开始和结束编号是应该在那里列表的开始和结束编号。但是,与现有列表一起,应提供应有的开始和结束编号。因此,如果应该有数字1到1000,并且实际上只有30到100,那么这将只显示缺少的30到100之间的数字。 – STH

+0

你应该更新你的问题来澄清这一点。我正在研究类似于这个答案的东西,但是不会从你原来的Q中猜出你的需求...... – chris

+0

我很抱歉,我看到它可能会被误解。感谢您尝试帮助。它已更新。 – STH

1
def find_missing_range(my_numbers, range_min, range_max): 
    expected_range = set(range(range_min, range_max + 1)) 
    return expected_range - set(my_numbers) 

def numbers_as_ranges(numbers): 
    ranges = [] 
    for number in numbers: 
     if ranges and number == (ranges[-1][-1] + 1): 
      ranges[-1] = (ranges[-1][0], number) 
     else: 
      ranges.append((number, number)) 
    return ranges 

def format_ranges(ranges): 
    range_iter = (("%d" % r[0] if r[0] == r[1] else "%d-%d" % r) for r in ranges) 
    return "(" + ", ".join(range_iter) + ")" 

def main(my_numbers, range_min, range_max): 
    numbers_missing = find_missing_range(my_numbers, range_min, range_max) 
    ranges = numbers_as_ranges(numbers_missing) 
    return format_ranges(ranges) 

if __name__ == '__main__': 
    range_min, range_max = 1, 40 
    print main([1, 4, 6, 10, 12], range_min, range_max) 
    print main([1, 2, 3, 4, 10, 20], range_min, range_max) 

(2-3, 5, 7-9, 11, 13-40) 
(5-9, 11-19, 21-40)