python中的SQL递归

问题描述

我正在使用熊猫read_csv从2个csv中读取数据。

Details.csv

ID,VALID
P1,Yes
P2,No
P3,Yes
P4,No

Relations.csv

ParentID,ChildID
P1,C1
P1,C2
C1,C1A
C2,C2A
C1A,C1AA
P2,D1
P2,D2
D2,D2A
D2A,D2AA
P3,C4
P4,C5

现在我将两者都存储在单独的数据框中。我必须检查DetailsRelationship的ID,并为每个ID找到其所有子级(直到没有其他子级)。如果该ID的有效期列中有Yes,则其所有子项都应具有“ VALID”(有效),否则所有子项都应具有“ NOT VALID”。

预期产量

P1,VALID
C1,VALID
C2,VALID
C1A,VALID
C2A,VALID
C1AA,VALID
P2,NOT VALID
D1,NOT VALID
D2,NOT VALID
D2A,NOT VALID
D2AA,NOT VALID
P3,VALID
C4,VALID
P4,NOT VALID
C5,NOT VALID

目前,我正在用sql执行此操作。我不知道如何在python中复制它。熊猫有没有可用的功能,或者我与for循环有关。任何建议将不胜感激。

在此question上,我尝试了以下类似操作,但无法正常工作。

import pandas as pd

details = pd.read_csv('C:/Myfolder/Python/Details.csv')
relationship = pd.read_csv('C:/Myfolder/Python/Relationship.csv')

def nlevel(details.id,parent_dict=relationship.ParentID,_cache={0:0}):
if details.id in _cache:
    return _cache[details.id]

return 1+nlevel(parent_dict[details.id],parent_dict)

解决方法

您可以使用堆栈递归地执行此操作。首先,将元素放入adjacency list中以简化遍历,然后清空堆栈,为每个节点添加子代并将有效性字符串存储在单独的结构中。保留顺序,从有序的节点有效性对中构建结果数据框,然后转储到CSV。

import pandas as pd
from collections import defaultdict

details_df = pd.read_csv("Details.csv")
relationship_df = pd.read_csv("Relationship.csv")
order = {k: 1 for k in relationship_df.values.flatten()}
graph = defaultdict(list)
validity = {}

for parent,child in relationship_df.values:
    graph[parent].append(child)

for root,valid in details_df.values:
    stack = [root]

    while stack:
        curr = stack.pop()
        validity[curr] = "VALID" if valid == "Yes" else "NOT VALID"
        stack.extend(graph[curr])

result_df = pd.DataFrame([[x,validity[x]] for x in order])
print(result_df.to_csv(index=False,header=False))

输出:

P1,VALID
C1,VALID
C2,VALID
C1A,VALID
C2A,VALID
C1AA,VALID
P2,NOT VALID
D1,NOT VALID
D2,NOT VALID
D2A,NOT VALID
D2AA,NOT VALID
P3,VALID
C4,VALID
P4,NOT VALID
C5,NOT VALID