Python 从功能上重写一个区间并集算法

Python 从功能上重写一个区间并集算法,python,algorithm,functional-programming,Python,Algorithm,Functional Programming,假设我们有一个区间数组[(a1,b1),(a2,b2),…,(an,bn)]按照起始位置和长度排序。我们想把所有相交的区间统一起来。以下是一个小样本数据集,其中至少包含两组独立的区间: from random import randint def gen_interval(min, max): return sorted((randint(min, max), randint(min, max))) sample = sorted([gen_interval(0, 100) for

假设我们有一个区间数组
[(a1,b1),(a2,b2),…,(an,bn)]
按照起始位置和长度排序。我们想把所有相交的区间统一起来。以下是一个小样本数据集,其中至少包含两组独立的区间:

from random import randint

def gen_interval(min, max):
    return sorted((randint(min, max), randint(min, max)))


sample = sorted([gen_interval(0, 100) for _ in xrange(5)] + 
                [gen_interval(101, 200) for _ in xrange(5)],
                key=lambda (a, b): (a, b - a))
还有几个函数,我们需要检查交叉点并延长间隔

def intersects(interval1, interval2):
    a1, b1 = interval1
    a2, b2 = interval2
    return (a1 <= a2 <= b1) or (a1 <= b2 <= b1)


def extend(interval1, interval2):
    a1, b1 = interval1
    a2, b2 = interval2
    return (a1, b2) if b2 > b1 else (a1, b1)
但是我想用函数式编程重写这个。我最接近的镜头是:

subsets = []
for interval in sample:
    if subsets and any(intersects(x, interval) for x in subsets[-1]):
        subsets[-1].append(interval)
    else:
        subsets.append([interval])

result = map(lambda x: reduce(extend, x), subsets)

这里一半的工作是在功能上完成的,但我仍然必须使用命令式方法拆分初始数组。如何使用纯函数式编程完成这件事?先谢谢你

您已接近使用
reduce
。此解决方案使用reduce累积折叠间隔的列表

def unite_intervals(intervals):
    def f(acc, element):
        if acc and intersects(acc[-1], element):
            return acc[:-1] + [extend(acc[-1], element)]
        else:
            return acc + [element]
    return reduce(f, intervals, [])

此外,由于我正在列表对象上使用
+
来累积结果,因此这会进行大量的重新分配。对于非常大的列表,这将是低效的。您可以考虑使用类似于
pyresistent
库的工具,以便更高效地积累数据结构。

我不确定您想要什么;你能详细解释一下“使用纯函数编程分割初始数组”是什么意思吗?第一种方法非常好,可读性很好,而第二种方法是人为放大的,更难理解。我们的目标是编写可读和可理解的代码,我真的看不出“纯函数式编程”的用武之地。@cPhase在我的问题中没有这样一行。然而,我的意思是,我的半支持函数式解决方案必须依赖命令式代码将初始排序的数组划分为子数组,在子数组中,间隔形成一个连续统一体,而我希望算法是纯函数式的。是否要删除(替换)for语句的
?如果您正在寻找类似于
sample.each()
的东西,请看一看Ruby。@EliKorvigo您能演示gen\u interval是什么函数吗?谢谢。我一回到笔记本电脑就研究你的解决方案。我还添加了
gen_interval
实现。谢谢你指出这一点。@EliKorvigo-谢谢,我已经用gen_间隔对你的解决方案进行了测试,它看起来与我的解决方案相匹配。用
替换
else:return acc+[element]
会与
return acc.append(element)或acc
抵触功能纯度吗?这将极大地提高性能。因此,这取决于你想要多纯洁。在这种情况下,它不会是一个“可观察的”副作用,因此对于unite_区间的调用方来说,它仍然是一个纯函数。因此,我想说,它会产生一个纯函数,但它不会是一个函数“公式”。无论我们做什么,代码显然会比命令式代码运行得慢,但性能在这里并不重要。非常感谢你的代码。
def unite_intervals(intervals):
    def f(acc, element):
        if acc and intersects(acc[-1], element):
            return acc[:-1] + [extend(acc[-1], element)]
        else:
            return acc + [element]
    return reduce(f, intervals, [])