我正在尝试确定迭代值列表的最佳方法,以查找包含其他范围的范围。 即范围8-18包括范围10-14
my_range_list = [[1, 1], [2, 8], [3, 16], [4, 16], [15, 25],[14,26]]
# should be the following:
# 3,16 encompasses 4,16 (4-16)
# 3,16 does not encompass 2,8 (2-8)
largest_range_list = []
for my_range in my_range_list:
my_lowr = my_range[0]
my_hir = my_range[1]
new_range_list =[]
encompassed=0
for largest_range in largest_range_list:
largest_lowr = largest_range[0]
largest_hir = largest_range[1]
if (my_lowr < largest_lowr) and (my_hir > largest_hir):
new_range_list.append(my_range)
encompassed = 1
break
if (largest_lowr <= my_lowr) and (largest_hir >= my_hir):
new_range_list.append(largest_range)
encompassed = 1
break
new_range_list.append(largest_range)
largest_range_list = new_range_list
if (not(encompassed == 1)):
largest_range_list.append(my_range)
print ("largest_range_list=" + ' '.join(map(str, largest_range_list)))
我考虑过事后替换,但由于large_range_list
不断变化,因此无效。还想知道哪种方式最蟒蛇(我来自Perl)。
我应该看什么?起始列表是良好的结构还是应该是不同的(范围列表)?
答案 0 :(得分:1)
您可以将迭代简化为:
my_range_list = [[1, 1], [2, 8], [3, 16], [4, 16], [5, 25]]
large_range_list = [[1, 1]]
for my_lowr, my_hir in my_range_list:
for large_lowr, large_hir in large_range_list:
if (my_lowr <= large_lowr) and (my_hir >= large_hir):
print("Range ({}, {}) encompasses ({}, {}).".format(
my_lowr, my_hir, large_lowr, large_hir))
我已将条件更改为与您的示例匹配(3,16 encompasses 4,16 (4-16)
)。
如果没有更改,它将无效,因为右边界重叠并且原始条件(my_hir > large_hir
)将拒绝有效范围。左侧相同。
答案 1 :(得分:0)
如果你想一次性完成它......我就这样做......
myRanges = [(1,1),(2,8),(3,16),(4,16),(5,25)]
testRanges = [(0,0),(1,1),(2,8),(3,16),(5,25)]
[ str((tLo,tHi)) + ' IS enc by ' + str((mLo, mHi)) if (tLo >= mLo and tHi <= mHi)
else str((tLo,tHi)) + ' NOT enc by ' + str((mLo, mHi))
for tLo,tHi in testRanges
for mLo,mHi in myRanges]
取决于你的需要......如果你不需要按顺序对它们采取行动(在这种情况下打印一些东西),这是一种更清洁的方法。
encompassed = [
((tLo,tHi),(mLo, mHi))
for tLo,tHi in testRanges
for mLo,mHi in myRanges
if (tLo >= mLo and tHi <= mHi)]
notEncompassed = [
((tLo,tHi),(mLo, mHi))
for tLo,tHi in testRanges
for mLo,mHi in myRanges
if (tLo < mLo or tHi > mHi)]
然后采取行动,建立一个功能....
def printResults(resultList, printString):
for t,m in resultList:
print str(t) + ' ' + printString + ' ' + str(m)
printResults(encompassed, 'encompassed by')
(1, 1) encompassed by (1, 1)
(2, 8) encompassed by (2, 8)
(3, 16) encompassed by (3, 16)
(5, 25) encompassed by (5, 25)
我将列表列表转换为元组列表,因为它们总是长度为2 ......但语法列表也能正常工作。
另外,一般来说,列表理解是更多的“pythonic”&#39;方式与嵌套for循环的简单事物......
[(x,y) for x in [1,2,3] for y in [5,6,7] if x < 3]
优于
for x in [1,2,3]:
for y in [5,6,7]:
if x < 3:
print (x,y)
答案 2 :(得分:0)
一个更简单的函数来测试范围是否包含在其他范围内:
my_ranges = [[1, 1], [2, 8], [3, 16], [4, 16], [15, 25], [14, 26]]
is_encompassed_by = lambda a, b: a != b and (a[0] >= b[0] and a[1] <= b[1])
可以使用排列来比较每个范围与其他每个范围:
from itertools import permutations
encompassed_ranges = []
for a, b in permutations(my_ranges, 2):
if a not in encompassed_ranges: # to cut short if it is already there
if is_encompassed_by(a, b):
encompassed_ranges.append(a)
not_encompassed_ranges = [r for r in my_ranges if r not in encompassed_ranges]
如果原件中有重复,则此最终列表可能会重复。
编辑:我的第一种方法如下,但考虑到ShadowRanger的相关评论,我将其更改为上面的解决方案
您可以使用可用于在Python中使用集合的操作来处理它:
rng_to_set = lambda rng: set(range(rng[0], rng[1]))
encompasses = lambda a, b: rng_to_set(a).issuperset(rng_to_set(b))
encompassed_by = lambda a, b: rng_to_set(a).issubset(rng_to_set(b))
l = [[1, 1], [2, 8], [3, 16], [4, 16], [5, 25]]
print ( encompasses( l[2] , l[3] ) ) # True
print ( encompassed_by( l[4] , l[2] )) # False
print ( encompassed_by( l[3] , l[2] )) # True