迭代两个列表,执行函数并返回值

时间:2016-10-03 10:29:18

标签: python

我试图迭代两个相同长度的列表,并且对于每个索引的一对条目,执行一个函数。该功能旨在对条目进行聚类 根据函数返回值的某些要求X。

问题清单如下:

e_list = [-0.619489,-0.465505, 0.124281, -0.498212, -0.51]      
p_list = [-1.7836,-1.14238, 1.73884, 1.94904, 1.84]  

并且该函数需要4个条目,l1和l2的每个组合。 该函数定义为

def deltaR(e1, p1, e2, p2):
    de = e1 - e2                                                                                                                                                                     
    dp = p1 - p2                                                                                                                                                           
    return de*de + dp*dp

到目前为止,我已经能够同时循环列表:

for index, (eta, phi) in enumerate(zip(e_list, p_list)):                                                                                                                    
    for index2, (eta2, phi2) in enumerate(zip(e_list, p_list)):                                                                                                             
        if index == index2: continue             # to avoid same indices                                                                                                                                   
        if deltaR(eta, phi, eta2, phi2) < X:                                                                                                                                      
             print (index, index2) , deltaR(eta, phi, eta2, phi2)

这个循环对每个组合执行函数,除了那些相同的函数,即索引0,0或1,1等

代码的输出返回:

(0, 1) 0.659449892453
(1, 0) 0.659449892453
(2, 3) 0.657024790285
(2, 4) 0.642297230697
(3, 2) 0.657024790285
(3, 4) 0.109675332432
(4, 2) 0.642297230697
(4, 3) 0.109675332432

我试图返回上述条件后全部匹配的索引数。换句话说,要将输出重新排列为:

output = [No. matched entries]

output = [2, 3]

2来自指数0和1匹配的事实

3来自指数2,3和4都匹配的事实

我想到的一种可能的方法是附加到列表,所有使用的索引,以便我返回

output_list = [0, 1, 1, 0, 2, 3, 4, 3, 2, 4, 4, 2, 3]

然后,我使用defaultdict计算出现次数:

for index in output_list:
    hits[index] += 1

从dict我可以操纵它返回[2,3]但是有更多的pythonic方法来实现这个目标吗?

1 个答案:

答案 0 :(得分:2)

这是查找图表的连接组件,一旦您从该视图中重新查看问题,就会非常容易并且有详细记录。

两个列表中的数据分散注意力。我将把数据视为zip(e_list,p_list)。将此视为图形,在这种情况下有5个节点(但在不同的数据集上可能有更多节点)。使用这些节点构建图形,如果它们通过了距离测试,则将它们与边缘连接起来。

从那里,您只需要确定无向图的连通分量,这在许多地方都有所涉及。以下是此网站上的基本深度优先搜索:Find connected components in a graph

循环遍历节点一次,执行DFS以查找所有连接的节点。查看节点后,将其标记为已访问,因此不会再次计算。要以您想要的格式获得答案,只需计算从每个未访问的起始点找到的未访问节点的数量,并将其附加到列表中。

------------------------ graph theory --------------------- -

您有要分解为相关组的数据点。这是数学和计算机科学中的一个主题,称为图论。见:https://en.wikipedia.org/wiki/Graph_theory

您有数据点。想象一下,将它们作为直角坐标绘制在eta phi空间中,然后在彼此接近的点之间绘制线条。你现在有一个&#34;图表&#34;有顶点和边缘。

要确定这些点中哪一个点之间有线条,请找到连接的组件。显然它很容易看到,但是如果你有数千个点,并且你想让计算机快速找到连接的组件,你可以使用图论。

假设我用zip(e_list,p_list)列出了所有eta phi点,列表中的每个条目都是一个顶点。如果您将图表存储在&#34;邻接列表&#34;格式,然后每个顶点也将有一个传出边的列表,将它连接到另一个顶点。

查找连接的组件实际上就像查看每个顶点一样简单,通过它添加一个复选标记,然后跟随每一行到下一个顶点并在其中放置一个复选标记,直到找不到任何其他连接的顶点。现在找到没有复选标记的下一个顶点,并重复下一个连接的组件。

作为一名程序员,您知道当您可以使用已发布和已审核的代码来处理任务时,为常见问题编写自己的数据结构是一个坏主意。 Google&#34; python图形模块&#34;。评论中提到的一个例子是&#34; pip install networkx&#34;。如果你在networkx中构建图形,你可以将连接的组件作为列表列表,然后取每个列表的len来获得你想要的格式:[len(_)for _ in nx.connected_components(G)]

---------------- code -------------------

但是如果你不理解数学,那么你可能不了解图形模块,也不理解基础python实现,但如果你只看一些链接就很容易了。基本上是点和线,但是在应用概念时非常有用,正如您所看到的那样,您的问题只不过是一个非常简单的图形理论问题。

我的图表是一个基本列表,因此顶点实际上没有名称。它们由列表索引标识。

e_list = [-0.619489,-0.465505, 0.124281, -0.498212, -0.51]      
p_list = [-1.7836,-1.14238, 1.73884, 1.94904, 1.84]  

def deltaR(e1, p1, e2, p2):
    de = e1 - e2                                                                                                                                                                     
    dp = p1 - p2                                                                                                                                                           
    return de*de + dp*dp

X = 1 # you never actually said, but this works

def these_two_particles_are_going_the_same_direction(p1, p2):
    return deltaR(p1.eta, p1.phi, p2.eta, p2.phi) < X

class Vertex(object):
    def __init__(self, eta, phi):
        self.eta = eta
        self.phi = phi
        self.connected = []
        self.visited = False

class Graph(object):
    def __init__(self, e_list, p_list):
        self.vertices = []
        for eta, phi in zip(e_list, p_list):
            self.add_node(eta, phi)

    def add_node(self, eta, phi):
        # add this data point at the next available index
        n = len(self.vertices)
        a = Vertex(eta, phi)

        for i, b in enumerate(self.vertices):
            if these_two_particles_are_going_the_same_direction(a,b):
                b.connected.append(n)
                a.connected.append(i)

        self.vertices.append(a)

    def reset_visited(self):
        for v in self.nodes:
            v.visited = False

    def DFS(self, n):
        #perform depth first search from node n, return count of connected vertices
        count = 0
        v = self.vertices[n]
        if not v.visited:
            v.visited = True
            count += 1
            for i in v.connected:
                count += self.DFS(i)
        return count

    def connected_components(self):
        self.reset_visited()
        components = []
        for i, v in enumerate(self.vertices):
            if not v.visited:
                components.append(self.DFS(i))                
        return components

g = Graph(e_list, p_list)
print g.connected_components()