如何利用Python读取一个记录家庭结构信息的文件,并形成家庭树

我有一个CSV文件,和下图相似。我尝试用递归方式构建家庭树,但是失败了。另,我想实现一个功能比如说,通过一个家庭ID获取整个家族一共有几代人。感谢各位大牛!

 

你好,代码已经写好了。能够成功的生成树,请采纳,采纳后私信发给你。

 先把每一行都建立成一个对象,然后去匹配关系

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 28 21:03:34 2021

@author: sosome
"""

import re
a = '''10001,123456,10006,10007,10005,10003,10004,
10002,123456,10006,10007,,,,
10003,123456,10001,,10008,10010,,
10004,123456,10001,,,,,
10005,123456,,,10001,,,
10006,123456,,,10007,10001,,
10007,123456,,10009,10006,10001,,
10008,123456,,,10003,10010,,
10009,123456,,,,10007,,
10010,123456,10003,10008,,,,
'''
b = re.findall(r'[^\r\n]+',a)
c = 'PersonID,FamilyID,FatherID,MotherID,SpouseID,Children1ID,Children2ID,ChildreNID'.split(',')
def p(a):
    x = a.split(',')
    r = {}
    for i in range(len(x)):
        r[c[i]] = x[i]
    r['ChildrenList'] = []
    return r

f = []
for i in b:
    f.append(p(i))
    
t = f[0]

def setParent(t,f):
    l = len(f)
    arr = f.copy()
    for i in arr:
        if i['FatherID'] == t['PersonID']:
            t['ChildrenList'].append(i)
            f.remove(i)
        if i['PersonID'] == t['FatherID']:
            f.remove(i)
            i['ChildrenList'].append(t)
            t = i
        if t['MotherID'] == i['PersonID']:
            f.remove(i)
        if i['SpouseID'] == t['PersonID'] and len(t['ChildrenList'])>0:
                f.remove(i)
    if l == len(f):
        for j in range(len(t['ChildrenList'])):
            t['ChildrenList'][j] = setParent(t['ChildrenList'][j],f)
        return t
    else:
        return setParent(t,f)
f = f[1:]
t = setParent(t,f)

#print(f)
#print(t)

def makeTree(t,lv=1):
    r = {'id':t['PersonID'],'lv':lv,'child':[]}
    print('* - '*lv+':'+t['PersonID'])
    for i in t['ChildrenList']:
        c = makeTree(i,lv+1)
        r['child'].append(c)
    return r

tree = makeTree(t)

#print([n['PersonID'] for n in t['arr']])

print(tree)


* - :10006
* - * - :10001
* - * - * - :10003
* - * - * - * - :10010
* - * - * - :10004
* - * - :10002

{'id': '10006', 'lv': 1, 'child': [{'id': '10001', 'lv': 2, 'child': [{'id': '10003', 'lv': 3, 'child': [{'id': '10010', 'lv': 4, 'child': []}]}, {'id': '10004', 'lv': 3, 'child': []}]}, {'id': '10002', 'lv': 2, 'child': []}]}
import re
a = '''10001,123456,10006,10007,10005,10003,10004,
10002,123456,10006,10007,,,,
10003,123456,10001,,10008,10010,,
10004,123456,10001,,,,,
10005,123456,,,10001,,,
10006,123456,,,10007,10001,,
10007,123456,,10009,10006,10001,,
10008,123456,,,10003,10010,,
10009,123456,,,,10007,,
10010,123456,10003,10008,,,,
'''
b = re.findall(r'[^\r\n]+',a)
c = 'PersonID,FamilyID,FatherID,MotherID,SpouseID,Children1ID,Children2ID,ChildreNID'.split(',')
def p(a):
    x = a.split(',')
    r = {}
    for i in range(len(x)):
        r[c[i]] = x[i]
    return r

f = []
for i in b:
    f.append(p(i))

f[0]['lv'] = 0

def makeLv(f):
    r = []
    for x in range(len(f)):
        i = f[x]
        if 'lv' not in i.keys():
            r.append(i['PersonID'])
            continue
        for y in range(len(f)):
            j = f[y]
            if x==y:
                continue
            if 'lv' in j.keys():
                continue
            if j['SpouseID'] == i['PersonID']:
                j['lv'] = i['lv']
            if j['FatherID'] == i['PersonID'] or j['MotherID'] == i['PersonID']:
                j['lv'] = i['lv'] + 1
            if j['Children1ID'] == i['PersonID']:
                j['lv'] = i['lv'] - 1
            if j['Children2ID'] == i['PersonID']:
                j['lv'] = i['lv'] - 1
    if len(r)>0:
        f = makeLv(f)
    return f

f = makeLv(f)

lv = {n['PersonID']:n['lv'] for n in f}
m = min([n['lv'] for n in f])
nt = {}

for i in lv:
    k = str(lv[i]+abs(m)+1)
    if k in nt.keys():
        nt[k].append(i)
    else:
        nt[k] = [i]

lv = [n for n in nt]
lv.sort()
for i in lv:
    print(i,nt[i])



1 ['10009']
2 ['10006', '10007']
3 ['10001', '10002', '10005']
4 ['10003', '10004', '10008']
5 ['10010']

 

这个 C# winform 可以做到,这个让我在想想

1. 建立一个person类,每一列是一个属性

2. 每一行是一个对象,初始化

3. 输入一个对象,根据其属性迭代构造出对应的树关系

这个是我写的部分程序,但是弄不清楚了。

'''
Created on 2021年5月23日

@author: xiang
'''
import csv
from Person import*


#该办法去掉了重复的家庭代码,得到了一组不重复的家庭代码
def getFamilyIdList(familylist):
    famlilyIdList=[]
    for item in familylist:
        if item not in famlilyIdList:
            famlilyIdList.append(item)     
    return  famlilyIdList

#该方法构建了一个按照家庭id分组的列表,且列表中每一个节点存储的依旧是一个家庭成员列表
def setFamilyGroup(personlist,familyIdlist):
    FamilyGrouplist=[]
    whole_famlilyGroupList=[]  
    for fid in familyIdlist:
        for person in personlist:
            if fid==person.fid18:
                FamilyGrouplist.append(person)
                whole_famlilyGroupList.append(FamilyGrouplist)
    return whole_famlilyGroupList   



#该方法可以会根据一个人的ID,寻找到这个人
def findPerson(personid,familylist):
    me=None
    for person in familylist:
        if person.pid==personid:
            me=person

    return me

#该方法根据我这个人找到母亲
def find_mother(me,familylist):     
    motherID=me.pid_a_m
    mother=me
    for person in familylist:
        if person.pid_a_m==motherID:
            mother=findPerson(motherID,familylist)
                   
        else:
            mother=object
    if mother!=me:        
        print('我的ID是:'+person.pid+'我母亲的ID是:'+mother.pid)  
    return mother

#该方法根据我个人找到父亲
def find_father(me,familylist):
    fatherID=me.pid_a_f
    father=me  
    for person in familylist:
        if person.pid_a_f==fatherID:
            father=findPerson(fatherID,familylist)            
        else:
            father=me
    if father!=me:
        print('我的ID是:'+person.pid+'我父亲的ID是:'+father.pid)  
    return father
    

#该方法尝试利用递归构建家庭树
def build_familyTree(me,familylist):
    me=find_father(me,familylist)
    build_familyTree(me,familylist)
    me=find_mother(me,)
    build_familyTree(me,familylist)            
            
                        

#这是主程序入口
if __name__ == '__main__':   
    with open('fmailycontmatch2.csv','r',encoding='utf-8') as f:
        reader=csv.DictReader(f) 
        personlist=[]
        familylist=[]
        familyIdlist=[]
        wholeFamilyGrouplist=[]
        fatherlist=[]
        for row in reader:
            person =Person(row['fid18'],
                           row['pid'],
                           row['pid_a_f'],
                           row['pid_a_m'],
                           row['pid_a_s'],
                           row['pid_a_c1'],
                           row['pid_a_c2'],
                           row['pid_a_c3'],
                           row['pid_a_c4'],
                           row['pid_a_c5'])
            personlist.append(person)
        for person in personlist:  

#将所有的人员家庭ID加入到家族列表里,这里还有重复的
            familylist.append(person.fid18)

#得到一个家庭的列表 
        familyIdlist=getFamilyIdList(familylist)
        
#得到按照家庭列表的全部列表        
        wholeFamilyGrouplist=setFamilyGroup(personlist,familyIdlist)                
        for familylist in wholeFamilyGrouplist:
            for me in familylist:
                build_familyTree(me,familylist)
    

 


class Person(object):
    class_name="被访问对象"
     
    def __init__(self,fid18,pid,pid_a_f,pid_a_m,pid_a_s,pid_a_c1,pid_a_c2,pid_a_c3,pid_a_c4,pid_a_c5):
        self.fid18=fid18
        self.pid=pid
        self.pid_a_f=pid_a_f
        self.pid_a_m=pid_a_m
        self.pid_a_s=pid_a_s
        self.pid_a_c1=pid_a_c1
        self.pid_a_c2=pid_a_c2
        self.pid_a_c3=pid_a_c3
        self.pid_a_c4=pid_a_c4
        self.pid_a_c5=pid_a_c5
        
        

        

 

源数据来源于这里,https://blog.csdn.net/weixin_54194510?spm=1010.2135.3001.5343

你这问题,让我想起我2011年写过的一个家族树项目,前端用 actionscript3 + javascript + html + css,后端数据用 php写 接口返回。

原理就是把数据组装成一个无限级的层级关系数据

前段时间写过类似的需求。思路就是建立嵌套字典然后转树绘图,首先是获取父子关系,获得这个形式的数据{'parent_id':'id'}。 然后把数据塞到字典里面去,这个过程中记录递归的次数就知道有几代人了。

# 将链表数据转换为树结构数据
def list_to_tree(data_list):
    res = {}
    for i, v in enumerate(data):
        v["parent_id"] = v["parent_id"] if v["parent_id"] else 0
        res.setdefault(v['parent_id'], {}).setdefault(f"{v['id']}", v['id'])
    return res

在CSDN答问题有mani吗?