Python 算法,列表元素之间的最近点

Python 算法,列表元素之间的最近点,python,python-3.x,algorithm,nested-lists,closest-points,Python,Python 3.x,Algorithm,Nested Lists,Closest Points,我有n个大小不等的有序列表(我事先不知道会有多少个列表)。我需要找到每个列表中一个元素之间的最小平均距离 例如,对于三个列表,n=3: a = [14, 22, 36, 48] b = [14, 23, 30, 72] c = [1, 18, 24] 输出应为(22,23,24),因为: mean(abs(22-23), abs(23-24), abs(22-24)) = 1.33333 在上面的例子中,这是所有点中最小的 我尝试用Python实现它,如下所示 def aligner(aoa

我有n个大小不等的有序列表(我事先不知道会有多少个列表)。我需要找到每个列表中一个元素之间的最小平均距离

例如,对于三个列表,n=3:

a = [14, 22, 36, 48]
b = [14, 23, 30, 72]
c = [1, 18, 24]
输出应为(22,23,24),因为:

mean(abs(22-23), abs(23-24), abs(22-24)) = 1.33333
在上面的例子中,这是所有点中最小的

我尝试用Python实现它,如下所示

def aligner(aoa):
'''
read arrays of arrays of peaks and return closest peaks
'''
#one of arrays is empty
if not [y for x in aoa for y in x]:
    return None
# there is the same nr in all array no need to do anything
candidate = set.intersection(*map(set, aoa))
if candidate:
    # returns intersect
    return [max(list(candidate))] * len(aoa)
else:
    #tried cartesian product via bumpy malloc err
    pass
我现在怀疑的是另一部分的执行情况。我曾想过使用笛卡尔积来生成所有的组合,但现在遇到了内存问题。我的猜测是,我会以某种方式生成所有的组合(可能是itertools??)并循环所有这些,但我不知道是否有任何算法可以解决这个问题,我可以使用

我不需要代码,只需要提示是否有任何有效的方法来解决这个问题,或者置换列表上使用n for循环的蛮力是唯一的方法

编辑

关于问题的大小,列表的nr最大为100(固定),而元素的nr可以变化,但我要说的是,每个列表有4或5个点的示例是一个现实的场景

所有的点都是非负的


尝试了建议的itertools解决方案,但当然没有内存问题,但已经运行了数小时,它被卡在了第三个元素上。

我不确定找到最佳解决方案的最佳方法,但一种启发式方法可能是检查范围。如果列表已排序,则可以使用二进制搜索检查列表中是否有某个元素在某个范围内。所以我们可以分而治之,试图缩小包含每个列表中一个元素的范围。由于平均值计算的性质,我们可能会对包含许多但不是所有列表中的元素的范围感兴趣,因为一组非常接近的数字和一些异常值可能会产生较小的平均差,而不是较小范围内的更多变化;这使解决方案变得相当复杂。

此方法是一种蛮力方法,但使用了一种类似于Dijkstra算法的消除方法,从而导致更少的情况(使算法最有可能快几个数量级,尤其是对于大列表或大量列表)。如果你不明白,告诉我,我可以澄清。可在以下位置找到实现:

您正在做的是列出不同的数字组合(即答案)?开始时最好(指数0),结束时最差,反之亦然,看看什么效果最好。您将只为第一个输入列表创建结果列表,而完全忽略其他输入列表。当然,对于一个列表,所有项目都是解决方案-它们的总差异为0。所以只需将第一个输入列表复制到结果列表中

接下来,可能会有一个while循环,遵循这个算法。从结果列表中取出最上面的项目并将其弹出。储存它的价值。转到下一个输入列表,对于下一个输入列表中的每个项目,制作一份您刚才弹出的顶部项目的副本,该项目也包含下一个输入列表中的项目。找到新的总体差异,并将基于该差异的新项目插入列表中。重复此操作,直到顶部解决方案包含所有列表。这意味着您可以保证您拥有最佳的解决方案(至少是联合第一),同时在显然不是解决方案的组合上花费的时间要少得多

  • 例如 括号内的数字为总差值)

    [14,22,36,48] [14, 23, 30, 72] [1,18,24]

结果列表是
[14(0)、22(0)、36(0)、48(0)]

  • 看看14。插入新数字[14和14(0)、22(0)、36(0), 48(0)、14和23(9)、14和30(16)、14和72(58)]
  • 看看14和14。插入新数字[22(0)、36(0)、48(0)、14和 14及18(8)、14及23(9)、14及30(16)、14及14及24(20)、14 及14及1(26)、14及72(58)]
  • 看看22。插入新的数字[36(0)、48(0)、22和23(1)、14 及14及18(8),22及14(8),22及30(8),14及23(9),14及30 (16) ,14及14及24(20)、14及14及1(26)、22及72(50)、14 和72(58)]
不停地重复,你最终的成绩是22、23、24。因为它包含所有n个列表,所以您可以停止并返回答案

要优化它,请执行以下操作:

  • 删除重复项
  • 也许可以以某种方式利用有序列表
  • 想一想,你把总差相同的项目放在哪里,也许是数字更多的项目放在第一位
编辑:
算法复杂度为O(n^2)

首先,优化差异的平均值与优化差异的总和是相同的

如果将问题建模为有向图,则可以解决此问题:

让列表为A、B、C。列表的每个条目都是图的顶点
v_ai
,其中A是列表,i是索引

对于A中的每个索引i,B中的每个索引j,添加一条边
v_ai->v_bj
,其宽度
abs(A(i)-B(j))

对于B中的每个索引i,C中的每个索引j,添加一条边
v_bi->v_cj
,其宽度
abs(B(i)-C(j))

对于C中的每个索引i,A中的每个索引j,添加一条边
v_ci->v_aj
,其宽度
abs(C(i)-A(j))


您现在要查找的是此图中的最小周期。将其用于O(n^3)算法。(改进的Floyd-Warshall算法)

我们对问题的大小知之甚少,例如,有多少个列表,以及每个列表有多少个元素。对于初学者和设置基线,您可以使用
itertools.product
迭代三个列表中所有可能的元素组合,而不在列表中实现它们。然后,您可以迭代它们并找到最好的一个,或者直接将它们传递到
min
中,并使用
itertools.compositions
sum
使用一个特殊的
函数来找到平均值最低的一个
>>> a = [14, 22, 36, 48]
>>> b = [14, 23, 30, 72]
>>> c = [1, 18, 24]
>>> len(list(itertools.product(a, b, c)))
48
>>> min(itertools.product(a, b, c),
...     key=lambda t: sum(abs(n-m) for n, m in itertools.combinations(t, 2)))
(22, 23, 24)