使用bisect来梳理具有距离条件的物品

时间:2015-09-25 17:25:05

标签: python python-3.x

在以下两个列表中

 l1 = [10, 33, 50, 67]
 l2 = [7, 16, 29, 65]

我使用bisect来组合两个列表中最接近的数字。我用这个代码

for s in l1:
    ind = bisect(l2, s, hi=len(l2) - 1)
    ind -= abs(l2[ind-1] - s) < l2[ind] - s
    print("{} -> {}".format(s, l2[ind]))

此代码提供输出:

10 -> 7
33 -> 29
50 -> 65
67 -> 65

为了摆脱第二个清单中的重复项目,我在打印后使用了这个:

    if ind == len(l2) - 1: break  

但是在if语句的情况下输出是:

10 -> 7
33 -> 29
50 -> 65

我想要的是,组合将以最接近的数字之间的距离不大于6的条件完成,但不会破坏未通过此测试的项目的循环,如我上一个代码的情况。我想要这个输出:

10 -> 7
33 -> 29
50 -> -- # here for the condition
67 -> 65

2 个答案:

答案 0 :(得分:2)

因为我们已经一分为二,所以我们知道哪些元素更大,所以我们可以在减去后进行测试:

from bisect import bisect
for s in l1:
    ind = bisect(l2, s, hi=len(l2) - 1)
    ind -= s - l2[ind-1] < l2[ind] - s
    tmp = l2[ind]
    print("{} -> {}".format(s,tmp if tmp  - s < 6 else "NULL"))

使用original question中的代码:

with open("test.txt") as f:
    r = re.compile("(\d+)")
    for line in f:
        a, b = line.lstrip("0123456789. ").split(">> ")
        a_keys = [int(i.group()) for i in r.finditer(a)]
        b_keys = [int(i.group()) for i in r.finditer(b)]
        a = a.strip("()\n").split(",")
        b = b.strip("()\n").split(",")
        for ele, k in zip(a, a_keys):
            ind = bisect(b_keys, k, hi=len(b) - 1)
            ind -= k - b_keys[ind] < b_keys[ind-1] - k
            print("{} -> {}".format(ele, b[ind] if abs(b_keys[ind] - k) < 5 else "NULL"))

输入:

1. (2- human rights, 10- workers rights)>> (3- droits de l'homme, 7- droit des travailleurs)
2. (2- human rights, 10- workers rights, 19- women rights)>> (1- droits de l'homme ,4- foobar, 15- les droits des femmes)

输出:

2- human rights -> 3- droits de l'homme
 10- workers rights ->  7- droit des travailleurs
2- human rights -> 1- droits de l'homme 
 10- workers rights -> NULL
 19- women rights ->  15- les droits des femmes

如果b_keys[ind]最接近的值+ n小于k我们匹配,否则我们输出null。

答案 1 :(得分:1)

我认为这只是检查你想要的元组的第二个值是什么。为了清晰起见,我已经重新制定了你正在做的事情(通过将打印问题与计算元组问题分开):

l1 = [10, 33, 50, 67]
l2 = [7, 16, 29, 65]

def bmap(s, lst):
    ind = bisect(lst, s, hi=len(lst) - 1)
    ind -= abs(lst[ind-1] - s) < lst[ind] - s
    # check that the result will be in bounds and return something appropriate
    return (s, lst[ind]) if abs(lst[ind] - s) < 6 else (s, "--")

result = [bmap(s, l2) for s in l1]
for (a, b) in result:
    print("{} -> {}".format(a,b))

请注意6是一个任意值,应该可以用常量或命名变量替换,这样读取代码的人就可以更好地理解发生了什么。

基本上我在这里所做的是设置一个函数来执行从单个任意值到任意列表成员的映射。然后我们在第一个列表中的每个值上运行该函数,并将第二个列表作为列表输入。最后,我们打印结果,而不是尝试将其作为映射函数的一部分。