Python 当有2对以上时,解决合并和顺序对问题
我想这会是一个简单的,也许是一行。但不是那么多 我有一个需要订购的成对对象的列表,必须合并相邻的成对对象。输入列表中对的原始顺序是随机的,没有重要性。在每一对中,我们可以确定第一个值永远不会大于第二个值。 看看这个例子中的整数 lst=[[1,4]、[17,20]、[2,3]、[16,18]、[6,6]、[6,7]、[9,13]、[21,24]] 如果出现以下情况,两对应合并:Python 当有2对以上时,解决合并和顺序对问题,python,algorithm,sorting,Python,Algorithm,Sorting,我想这会是一个简单的,也许是一行。但不是那么多 我有一个需要订购的成对对象的列表,必须合并相邻的成对对象。输入列表中对的原始顺序是随机的,没有重要性。在每一对中,我们可以确定第一个值永远不会大于第二个值。 看看这个例子中的整数 lst=[[1,4]、[17,20]、[2,3]、[16,18]、[6,6]、[6,7]、[9,13]、[21,24]] 如果出现以下情况,两对应合并: 它们是重叠的,例如[16,18]和[17,20]->[16,20] 他们是近邻,例如[17,20]和[21,24]-
- 它们是重叠的,例如[16,18]和[17,20]->[16,20]
- 他们是近邻,例如[17,20]和[21,24]->[17,24]
- 具体来说[6,6]和[6,7]也应该合并,成为[6,7]
def mrg2pairs(pair_a, pair_b):
""" Merge two pairs
:param pair_a: First pair
:param pair_b: Second pair
:return: A list of, one or two, pairs, each same format as pair_a and pair_b
"""
a1, a2 = pair_a[0], pair_a[1]
b1, b2 = pair_b[0], pair_b[1]
if a1 < b1:
if (b1 - a2) > 1: # a entirely before b
return [pair_a, pair_b] # return untouched
elif a2 == b1: # a-end touching b-start
return [[a1, b2]] # merge
else:
if a2 < b2: # a overlapping b-start
return [[a1, b2]]
else: # a encapsulating b
return [pair_a] # return a
else:
if a1 < b2:
if a2 > b2: # a overlapping b-end
return [[b1, a2]]
else: # a inside b
return [pair_b] # return b
else:
if (a1 - b2) > 1: # a entirely after b
return [pair_a, pair_b] # return untouched
else: # a-start touching b-end
return [[b1, a2]] # merge
def mrg2pairs(对a、对b):
合并两对
:参数对\u a:第一对
:参数对_b:第二对
:return:一对或两对的列表,每对的格式与对A和对b相同
"""
a1,a2=线对a[0],线对a[1]
b1,b2=线对_b[0],线对_b[1]
如果a11:#a完全在b之前
返回[对a,对b]#未动返回
elif a2==b1:#a端接触b端启动
返回[[a1,b2]]#合并
其他:
如果a2b2:#重叠的b端
返回[[b1,a2]]
其他:#a在b内
返回[配对b]#返回b
其他:
如果(a1-b2)>1:#a完全在b之后
返回[对a,对b]#未动返回
否则:#a-开始触摸b-结束
返回[[b1,a2]]#合并
该函数经过测试,工作正常-问题是如何在列表情况下从2线对情况转到n线对情况
我需要用Python解决这个问题-欢迎任何建议,但我更喜欢Python优雅。您可以使用对分模块获得O(NlogN)解决方案,而不需要实际排序:
lst = [[1, 4], [17, 20], [2, 3], [16, 18], [6, 6], [6, 7], [9, 13], [21, 24]]
from bisect import bisect_left
starts = [] # merged starting values
ends = [] # merged ending values
for (start,end) in lst:
iLeft = bisect_left(ends,start-1) # first position after start
iRight = bisect_left(starts,end+1) # first position after end
starts[iLeft:iRight] = [min([start]+starts[iLeft:iLeft+1])] # insert/merge
ends[iLeft:iRight] = [max([end]+ends[iRight-1:iRight])]
merged = list(zip(starts,ends)) # combine starts and ends
print(merged)
[(1, 4), (6, 7), (9, 13), (16, 24)]
与此同时,我自己也提出了这个解决方案——它是可行的,但我发现它并不像我希望的那样优雅。我相信@Alain T.是更好的解决方案,因为它至少更短
def mrg_many(lst_pairs):
""" Merge many pairs
:param lst_pairs: List of pairs
:return: A list of pairs, where all appropriate merges is made
"""
lst_ret = [itm for itm in lst_pairs] # deep copy
lst_rem = list()
for n in range(len(lst_pairs)):
for m in range(n+1, len(lst_pairs)):
mp_ret = mrg2pairs(lst_pairs[n], lst_pairs[m])
if len(mp_ret) == 1:
if mp_ret[0] not in lst_ret:
lst_ret.append(mp_ret[0])
lst_rem.extend([itm for itm in [lst_pairs[n], lst_pairs[m]] if itm not in mp_ret])
lst_resul = [itm for itm in lst_ret if itm not in lst_rem]
if any([itm not in lst_resul for itm in lst_pairs]): # at least one pair from input disappeared
return mrg_many(lst_resul)
return lst_resul
请发布您尝试过的代码以及您遇到的问题。谢谢Scott,但这更多的是一个算法问题,我没有任何代码-是的,那么您在算法方面的最佳尝试是什么?您可以使用reduce做一行程序,但我认为常规for循环更具可读性。首先对时间间隔进行排序,然后想想你会在纸上做什么。算法不能是“pythonic”。代码可以是pythonic。