【问题标题】:Given 2 list of integers how to find the non-overlapping ranges?给定 2 个整数列表如何找到不重叠的范围?
【发布时间】:2018-04-13 08:11:47
【问题描述】:

给定

x = [5, 30, 58, 72]
y = [8, 35, 53, 60, 66, 67, 68, 73]

目标是遍历x_i 并找到大于x_i 但不大于x_i+1y

假设两个列表都已排序并且所有项目都是唯一的,那么在给定 xy 的情况下所需的输出是:

[(5, 8), (30, 35), (58, 60), (72, 73)]

我试过了:

def per_window(sequence, n=1):
    """
    From http://stackoverflow.com/q/42220614/610569
        >>> list(per_window([1,2,3,4], n=2))
        [(1, 2), (2, 3), (3, 4)]
        >>> list(per_window([1,2,3,4], n=3))
        [(1, 2, 3), (2, 3, 4)]
    """
    start, stop = 0, n
    seq = list(sequence)
    while stop <= len(seq):
        yield tuple(seq[start:stop])
        start += 1
        stop += 1

x = [5, 30, 58, 72]
y = [8, 35, 53, 60, 66, 67, 68, 73]

r = []

for xi, xiplus1 in per_window(x, 2):
    for j, yj in enumerate(y):
        if yj > xi and yj < xiplus1:
            r.append((xi, yj))
            break

# For the last x value.
# For the last x value.
for j, yj in enumerate(y):
    if yj > xiplus1:
        r.append((xiplus1, yj))
        break

但是有没有更简单的方法可以通过numpypandas 或其他方式实现相同的目标?

【问题讨论】:

  • y 中有多个位于x[i]x[i+1] 之间的号码时,您希望发生什么?
  • 抢先。

标签: python list pandas numpy range


【解决方案1】:

我们可以在列表中使用pd.DataFramemerge_asofdirection = forward

new = pd.merge_asof(pd.DataFrame(x,index=x), pd.DataFrame(y,index=y),on=0,left_index=True,direction='forward')
out = list(zip(new[0],new.index))

如果您不需要完全匹配来匹配您需要将allow_exact_matches=False 传递给merge_asof

输出:

[(5, 8), (30, 35), (58, 60), (72, 73)]

【讨论】:

  • 其实最近的可能不能满足OP的需求,因为当你得到57插入的y = [8, 35, 53, 57 ,60, 66, 67, 68, 73]时,不会得到预期的结果
  • 哦,我明白了,我们可以使用 forward
  • 如果使用forward,x = [5, 30, 58,59,72]时可能不起作用。
  • 是的,现在我看到了缺点。
  • @Tangfeifan 我认为情况是问题评论中的意思不是吗。
【解决方案2】:

你可以使用numpy.searchsortedside='right'来找出y中第一个大于x的值的索引,然后提取具有索引的元素;一个简单的版本假设 y 中总是有一个值大于 x 中的任何元素 可能是:

x = np.array([5, 30, 58, 72])
y = np.array([8, 35, 53, 60, 66, 67, 68, 73])

np.column_stack((x, y[np.searchsorted(y, x, side='right')]))
#array([[ 5,  8],
#       [30, 35],
#       [58, 60],
#       [72, 73]])

给定y 已排序:

np.searchsorted(y, x, side='right')
# array([0, 1, 3, 7])

返回y 中大于x 中对应值的第一个值的索引。

【讨论】:

    【解决方案3】:

    您可以通过迭代 x 来构造一个新列表,该列表用自身压缩——偏移 1 个索引并附加 y 的最后一个元素——然后迭代 y,检查每次传递的条件并中断最里面的循环。

    out = []
    for x_low, x_high in zip(x, x[1:]+y[-1:]):
        for yy in y:
            if (yy>x_low) and (yy<=x_high):
                out.append((x_low,yy))
                break
    
    out
    # returns:
    [(5, 8), (30, 35), (58, 60), (72, 73)]
    

    【讨论】:

      【解决方案4】:
      def find(list1,list2):
          final = []
          for i in range(len(list1)):
              pos=0
              try:
                  while True:
                      if i+1==len(list1) and list1[i]<list2[pos]:
                          final.append((list1[i],list2[pos]))
                          raise Exception
                      if list1[i]<list2[pos] and list1[i+1]>list2[pos]:
                          final.append((list1[i],list2[pos]))
                          raise Exception
                      pos+=1
              except: pass
          return final
      

      【讨论】:

        猜你喜欢
        • 2018-12-11
        • 2013-02-21
        • 1970-01-01
        • 2013-07-25
        • 2012-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多