如何处理值范围列表

时间:2016-03-22 17:41:28

标签: python list

我正在尝试确定迭代值列表的最佳方法,以查找包含其他范围的范围。 即范围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)。

我应该看什么?起始列表是良好的结构还是应该是不同的(范围列表)?

3 个答案:

答案 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