【问题标题】:How to find overlapping tuples in a list and return overlapping tuples如何在列表中查找重叠元组并返回重叠元组
【发布时间】:2019-09-25 18:44:40
【问题描述】:

我目前有一个包含元组的列表。

overlap_list = [(10001656, 10001717), (700, 60000), (10001657, 10001718), (10001657, 10001716), (10031548, 10031643), (10031556, 10031656)]

我想要以下输出:

new_list=[(10001656, 10001717),(10001657, 10001718),(10001657, 10001716),(10031548, 10031643), (10031556, 10031656)]

元组内的数字是开始和结束边界。我想找到数字之间重叠的任何元组。

我已经尝试过我找到的这段代码,它提出了一个类似的问题:

import itertools as ittools

def pairwise(iterable):
    a, b = ittools.tee(iterable)
    next(b, None)
    return zip(a, b)

overlap_list = [(10001656, 10001717), (700, 60000), (10001657, 10001718), (10001657, 10001716), (10031548, 10031643), (10031556, 10031656)]
print([list(p) for k, p in it.groupby(pairwise(overlap_list), lambda x: x[0][0] < x[1][0] < x[0][1]) if k])

但这给出了:

[[((10031548, 10031643), (10031556, 10031656))]]

我查看了不同的解决方案,但我面临的问题是按之前的位置进行索引似乎不起作用。

如何获得所需的输出?任何帮助将不胜感激。

【问题讨论】:

  • 重叠是什么意思?
  • @DanielMesejo:例如:(10001656, 10001717),(10001657, 10001718):将元组视为range(start.value, end.value),因此第二个start.value (10001657) 在第一个元组的range 内。
  • 您想要的输出似乎包含两组不同的重叠元组而不改变原始列表的顺序,这是否意味着您只是试图过滤掉任何不与任何其他元组重叠的元组在列表中?而且你不关心输出顺序或分组?
  • @benvc:是的,你是对的,我想在列表中找到任何具有重叠值的元组。我不在乎输出的顺序。

标签: python python-3.x list tuples


【解决方案1】:

说实话 - 我并不真正了解您的代码及其背后的想法,因此无法告诉您为什么结果只包含所需元组的一个子集。

但是,我有一个不同的方法,您可能会觉得有趣。
主要思想是有一个函数可以测试两个元组是否重叠。 此函数适用于overlap_list 中的所有元组组合。如果两个重叠,则将它们添加到结果列表中,该列表随后将包含重复项,因此最后应用list(set(result))但是,你可以不列出演员表,因为一组都可以,结果是 imo...

test函数的思路是简单的对两个待测元组的4个值进行排序,看排序顺序(见numpy.argsort)。如果前两个索引是 0/1 或 2/3,则两个元组不重叠。
换句话说:针对&gt;1 进行测试,它们必须不相等,即不能同时为真或假:

def overlap_test(tpl1, tpl2):
    import numpy as np
    a, b = np.argsort(tpl1 + tpl2)[:2] > 1
    return a != b

这是使用函数的循环:

import itertools as it
result = []
for test_tpl, sec_tpl in list(it.combinations(overlap_list, 2)):
    if overlap_test(test_tpl, sec_tpl):
        result.extend([test_tpl, sec_tpl])
result = list(set(result))

# [(10001657, 10001718),
#  (10031556, 10031656),
#  (10031548, 10031643),
#  (10001657, 10001716),
#  (10001656, 10001717)]

我仍然想知道循环是否不能更高效一些,这样是否也无法优化对 set 的需求 - 好吧,也许你会找到一个更好的。


编辑:

到目前为止并没有真正发现什么不同,但有一点改进:

同样的方法,但从一开始就使用set

def find_overlap_tuples_0(tpl_list):
    result = set()
    for test_tpl, sec_tpl in list(it.combinations(tpl_list, 2)):
        if overlap_test(test_tpl, sec_tpl):
            result.add(test_tpl)
            result.add(sec_tpl)
    return list(result)

# %timeit find_overlap_tuples_0(overlap_list)
# 178 µs ± 4.87 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

有点不同,仅基于排列和分组(似乎稍微快一点)

def find_overlap_tuples_1(tpl_list):
    result = set()
    no_ovl = set()
    for a, grp in it.groupby(it.permutations(tpl_list, 2), lambda x: x[0]):
        for b in grp:
            if (a not in result) and (b[1] not in no_ovl):
                if overlap_test(*b):
                    result.add(b[0])
                    result.add(b[1])
                    break
                no_ovl.add(b[0])
    return list(result)

# %timeit find_overlap_tuples_1(overlap_list)
# 139 µs ± 1.59 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

  • 对不起,我花了这么长时间才回来。感谢您对估算两个元组的好建议。您的代码运行良好!
  • 无需道歉,如果有帮助我很高兴。但是,如果您有 - 除了明显重叠和不重叠的元组 - 还有 touching 元组,我的意思是共享相同边界的元组,例如 (2, 5)(5, 7),这可能会导致错误argsort 的想法,只是因为我不知道在这种情况下这个命令会创建哪个顺序......
【解决方案2】:

似乎您可以对列表进行排序,以便任何重叠的开始和停止都是相邻的,然后只需比较邻居以确定是否由于不重叠而需要过滤掉任何元组(在代码末尾排序不是必需的,只是为了更容易在打印输出中看到重叠的邻居)。

l = [(10001656, 10001717), (700, 60000), (10001657, 10001718), (10001657, 10001716), (10031548, 10031643), (10031556, 10031656)]

l.sort()
overlap = set()
for a, b in zip(l, l[1:]):
    if a[1] >= b[0] and a[1] <= b[1]:
        overlap.add(a)
    if b[0] >= a[0] and b[0] <= a[1]:
        overlap.add(b)

overlap = sorted(overlap)        
print(overlap)
# [(10001657, 10001716), (10001657, 10001718), (10031548, 10031643), (10031556, 10031656)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2015-03-12
    • 1970-01-01
    • 2013-12-12
    • 2013-07-25
    相关资源
    最近更新 更多