给定 2 个整数列表如何找到不重叠的范围?
Posted
技术标签:
【中文标题】给定 2 个整数列表如何找到不重叠的范围?【英文标题】:Given 2 list of integers how to find the non-overlapping ranges? 【发布时间】: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+1
的y
值
假设两个列表都已排序并且所有项目都是唯一的,那么在给定 x
和 y
的情况下所需的输出是:
[(5, 8), (30, 35), (58, 60), (72, 73)]
我试过了:
def per_window(sequence, n=1):
"""
From http://***.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
但是有没有更简单的方法可以通过numpy
、pandas
或其他方式实现相同的目标?
【问题讨论】:
当y
中有多个位于x[i]
和x[i+1]
之间的号码时,您希望发生什么?
抢先。
【参考方案1】:
我们可以在列表中使用pd.DataFrame
和merge_asof
和direction = 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.searchsorted
和side='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
【讨论】:
以上是关于给定 2 个整数列表如何找到不重叠的范围?的主要内容,如果未能解决你的问题,请参考以下文章
2021-07-16:三个无重叠子数组的最大和。给定数组 nums 由正整数组成,找到三个互不重叠的子数组的最大和。每个子数组的长度为k,我们要使这3*k个项的和最大化。返回每个区间起始索引的列表(索