【问题标题】:Excluding positions to create new intervals in python排除位置以在 python 中创建新间隔
【发布时间】:2014-03-22 00:22:11
【问题描述】:

假设我有一根长度为 0-5000 的绳索。我想把这条绳子分开,这样下面列表中的间隔就被剪掉了,剩下的被返回:

我的清单:

['HE670029', '4095', '4096']
['HE670029', '4098', '4099']
['HE670029', '4102', '4102']

所需的输出(不必是列表,可以写入文件每个list 换行):

['HE670029', '0', '4094']
['HE670029', '4097', '4097']
['HE670029', '4100', '4101']
['HE670029', '4103', '5000']

我尝试操作字典,但没有成功。我不知道如何将其转换为允许我执行所需操作的格式。

【问题讨论】:

  • 您的输入是否保证排序?间隔可以重叠吗?
  • 间隔不能重叠(它们都是沿绳索的不同点/间隔),并且很可能输入将被排序,但如果不必这样做会更好。

标签: python list


【解决方案1】:

它不漂亮,但它有效:

sections_to_cut = [
        ['HE670029', '4095', '4096'],
        ['HE670029', '4098', '4099'],
        ['HE670029', '4102', '4102']
    ]

ropes = {}
for rope in sections_to_cut:
    if rope[0] not in ropes: # could use default dict instead
        ropes[rope[0]] = []
    ropes[rope[0]].append((int(rope[1]), int(rope[2])))

cut_ropes = []

for rope_name, exclude_values in ropes.items():
    sorted_ex = sorted(exclude_values, key=lambda x: x[0])
    a = 0
    for i in sorted_ex:
        cut_ropes.append([rope_name, str(a), str(i[0]-1)])
        a = i[1] + 1
    cut_ropes.append([rope_name, str(a), str(5000)])

print(cut_ropes)
# [['HE670029', '0', '4094'], ['HE670029', '4097', '4097'], ['HE670029', '4100', '4101'], ['HE670029', '4103', '5000']]

【讨论】:

    【解决方案2】:

    在看到您的间隔不能重叠之前,我开始写这篇文章。这种方法有点矫枉过正,但我​​会放弃它,因为扔掉它似乎很浪费。

    见底部的简短解决方案。

    OOP 式的做事方式:

    class Interval:
        def __init__(self,left,right):
            self.left = int(left)
            self.right = int(right)
        def __contains__(self,x):
            return self.left <= int(x) <= self.right
    
    intervals = [['HE670029', '4095', '4096'],
    ['HE670029', '4098', '4099'],
    ['HE670029', '4102', '4102']]
    
    #if intervals aren't sorted, then do:
    #cuts = [Interval(*x[1:]) for x in sorted(intervals,key=lambda i: i[1])]
    cuts = [Interval(*x[1:]) for x in intervals]
    
    #this step is overkill, since we know our intervals can't overlap
    breakpoints = [x for x in range(1,5000) if any(x in cut for cut in cuts)]
    
    def gen_segments(breakpoints, id_='HE670029', start=0, end=5000 ):
        for pair in chunks(breakpoints,2):
            if len(pair) < 2: #last breakpoint may be singleton
                pair += pair
            left,right = pair
            yield id_, start, left-1
            start = right+1
        yield id_, start, end
    

    chunksthis 页面上的几个块配方之一。演示:

    list(gen_segments(breakpoints))
    Out[258]: 
    [('HE670029', 0, 4094),
     ('HE670029', 4097, 4097),
     ('HE670029', 4100, 4101),
     ('HE670029', 4103, 5000)]
    

    就像我说的那样,上面的内容太过分了。如果您知道间隔不重叠,则不需要花哨的Interval 类或任何东西。只需这样做:

    breakpoints = [int(x) for interval in intervals for x in interval[1:]]
    

    然后直接使用上面的gen_segments

    【讨论】:

      【解决方案3】:

      我不会为你剧透,而是给你一个提示。给定

      xs = [
          ['HE670029', '4095', '4096'],
          ['HE670029', '4098', '4099'],
          ['HE670029', '4102', '4102']]
      

      第一部分和最后一部分很容易做到。只是0->第一个节点,然后最后一个是5000。你需要中间值...

      首先创建可以提取绳索两端值的函数:

      def head(x): return int(x[1])
      def last(x): return int(x[-1])
      

      现在您需要像这样分隔每个后续行:

      [a,b for a,b in zip(xs[:-1], xs[1:])]
      

      现在既然你有了这些值,你可以继续使用你刚刚创建的函数来提取每个值的最后一个和第一个值...

      [(last(a),head(b)) for (a,b) in zip(xs[:-1], xs[1:])]
      

      这些不是你想要的价值观吗?你需要在这里移动一点......

      [(last(a)+1,head(b)-1) for (a,b) in zip(xs[:-1], xs[1:])]
      

      最后,只需将正确的列表放入:

      xM = [['HE670029', str(last(a)+1),str(head(b)-1)] for (a,b) in zip(xs[:-1], xs[1:])]    
      

      现在您有 2 个列表。 xsxM。我相信您可以循环播放并将它们组合在一起...如果您想改善结果,Ypu 可以考虑使用ziplistconcat

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多