Python CSV导入为复杂嵌套列表,排序,输出为文本或返回到CSV

2024-09-30 18:30:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据结构,我们称之为库存,在CSV中,类似于:

ResID,Building,Floor,Room,Resource
1.1.1.1,Central Park,Ground,Admin Office,Router
1.1.2.1,Central Park,Ground,Machine Closet,Router
1.3.1.1,Central Park,Mezzanine,Dungeon,Whip
2.1.3.1,Chicago,Roof,Pidgeon Nest,Weathervane
1.13.4.1,Central Park,Secret/Hidden Floor,c:\room,Site-to-site VPN for 1.1.1.1
1.2.1.1,Central Park,Balcony,Restroom,TP    

我正试图让它以排序的CSV格式输出,并以文本文件的格式输出,格式如下:

1 Central Park
1.1 Ground
1.1.1 Admin Office
1.1.1.1 Router
1.1.2 Machine Closet
1.1.2.1 Router
1.2 Balcony
1.2.1 Restroom
1.2.1.1 TP
1.3 Mezzanine
1.3.1 Dungeon
1.3.1.1 Whip
1.13 Secret/Hidden Floor
1.13.4 c:\room
1.13.4.1 Site-to-site VPN for 1.1.1.1
2 Chicago
2.1 Roof
2.1.3 Pidgeon Nest
2.1.3.1 Weathervane

我设想的数据结构类似于:

Building = {
    1 : 'Central Park',
    2 : 'Chicago'
}
Floor = {
    1 : {
        1 : 'Ground',
        2 : 'Balcony',
        3 : 'Mezzanine',
        13: 'Secret/Hidden Floor'
    },
    2  : {
        1 : 'Roof'
    }
}

Room = {
    1 : {
        1 : {
            1 : 'Admin Office',
            2 : 'Machine Closet'
        }
        2 : {
            1 : 'Restroom'
        }
        3 : {
            1 : 'Dungeon'
        }
... Hopefully by now you get the idea.

我的复杂之处在于,我不知道这是否是表示数据的最佳方式,然后将其迭代为:

for buildingID in buildings:
    for floorID in floors[buildingID]:
        for roomID in rooms[buildingID][floorID]:
            for resource in resources[buildingID][floorID][roomID]:
                do stuff...

或者,如果有一种更合理的方法来表示脚本中的数据,但我需要完整的文档标题编号和名称,而这是以我的技能水平来可视化的唯一方法。你知道吗

我也无法找到一种有效的方法来生成这些信息,并将其以这种格式从CSV构建到数据结构中。你知道吗

这对某些人来说似乎微不足道,但我并不是一个程序员,实际上只是偶尔涉猎。你知道吗

我的最终目标是能够将CSV吸收到一个合理的数据结构中,以升序数字顺序对其进行适当排序,在上面显示的文本结构中生成行条目,只列出一次每个建筑、楼层、房间和资源,并在上下文中相互列出,然后表面上看,这对我来说是微不足道的输出到文本或返回到排序的CSV。你知道吗

如有任何建议,我们将不胜感激。你知道吗

编辑:解决方案

利用下面我接受的答案,我能够生成以下代码。感谢那个删除了他的答案和评论的家伙,这也简化了我的排序过程!你知道吗

import csv

def getPaddedKey(line):
    keyparts = line[0].split(".")
    keyparts = map(lambda x: x.rjust(5, '0'), keyparts)
    return '.'.join(keyparts)

def outSortedCSV(reader):
    with open(fOutName, 'w') as fOut:
        writer = csv.writer(fOut, delimiter=',')
        head = next(reader)
        writer.writerow(head)
        writer.writerows(sorted(reader, key=getPaddedKey))

s = set()
fInName = 'fIn.csv'
fOutName = 'fOut.csv'

with open(fInName, 'r') as fIn:
    reader = csv.reader(fIn, delimiter=',')
    outSortedCSV(reader)
    fIn.seek(0)
    next(fIn)
    for row in reader:
        ids = row[0].split('.')      # split the id
        for i in range(1, 5):
            s.add(('.'.join(ids[:i]), row[i])) # add a tuple with initial part of id and name

for e in sorted(list(s), key=getPaddedKey):
    print e[0] + '  ' + e[1]

Tags: csvin数据结构parkfor排序格式reader
2条回答

如果没有理由构建建议的结构,只需为每行添加建筑、楼层、房间和资源及其id(以自动消除重复项)。然后将集合转换为一个列表,对其排序,就完成了。你知道吗

可能的Python代码,假设rd是清单(*)上的csv.reader

next(rd)                         # skip the headers line
s = set()
for row in rd:
    ids = row[0].split('.')      # split the id
    for i in range(1, 5):
        s.add(('.'.join(ids[:i]), row[i])) # add a tuple with initial part of id and name
l = list(s)                      # convert to a list
l.sort()                         # sort it

现在您有了一个2元组列表[('1', 'Central Park'), ('1.1', 'Ground'), ('1.1.1', 'Admin Office'), ...],您可以使用它来构建一个新的csv或将其打印为文本:

for i in l:
    print(" ".join(i))

(*)在Python 3中,您将使用:

with open(inventory_path, newline = '') as fd:
    rd = csv.reader(fd)
    ...

在Python 2中,应该是:

with open(inventory_path, "rb") as fd:
    rd = csv.reader(fd)
    ...

提取身份证

ids = ['Building_id', 'Floor_id', 'Room_id', 'Resource_id']
labels = ['ResID', 'Building', 'Floor', 'Room', 'Resource']

df2 = df.join(pd.DataFrame(list(df['ResID'].str.split('.')), columns=ids))
 df2
    ResID   Building    Floor   Room    Resource    Building_id     Floor_id    Room_id     Resource_id
0   1.1.1.1     Central Park    Ground  Admin Office    Router  1   1   1   1
1   1.1.2.1     Central Park    Ground  Machine Closet  Router  1   1   2   1
2   1.3.1.1     Central Park    Mezzanine   Dungeon     Whip    1   3   1   1
3   2.1.3.1     Chicago     Roof    Pidgeon Nest    Weathervane     2   1   3   1
4   1.13.4.1    Central Park    Secret/Hidden Floor     c:\room     Site-to-site VPN for 1.1.1.1    1   13  4   1
5   1.2.1.1     Central Park    Balcony     Restroom    TP  1   2   1   1

重复这个

小助手方法

def pop_list(list_):
    while list_:
        yield list_[-1], list_.copy()
        list_.pop()


for (id_, remaining_ids), (label, remaining_labels) in zip(pop_list(ids), pop_list(labels)):

    print(label, ': ', df2.groupby(remaining_ids)[label].first())

退货

Resource :  Building_id  Floor_id  Room_id  Resource_id
1            1         1        1                                    Router
                       2        1                                    Router
             13        4        1              Site-to-site VPN for 1.1.1.1
             2         1        1                                     TP   
             3         1        1                                      Whip
2            1         3        1                               Weathervane
Name: Resource, dtype: object

Room :  Building_id  Floor_id  Room_id
1            1         1            Admin Office
                       2          Machine Closet
             13        4                 c:\room
             2         1                Restroom
             3         1                 Dungeon
2            1         3            Pidgeon Nest
Name: Room, dtype: object

Floor :  Building_id  Floor_id
1            1                        Ground
             13          Secret/Hidden Floor
             2                       Balcony
             3                     Mezzanine
2            1                          Roof
Name: Floor, dtype: object

Building :  Building_id
1    Central Park
2         Chicago
Name: Building, dtype: object

解释

for (id_, remaining_ids), (label, remaining_labels) in zip(pop_list(ids), pop_list(labels)):
    print((id_, remaining_ids), (label, remaining_labels))

退货

('Resource_id', ['Building_id', 'Floor_id', 'Room_id', 'Resource_id']) ('Resource', ['ResID', 'Building', 'Floor', 'Room', 'Resource'])
('Room_id', ['Building_id', 'Floor_id', 'Room_id']) ('Room', ['ResID', 'Building', 'Floor', 'Room'])
('Floor_id', ['Building_id', 'Floor_id']) ('Floor', ['ResID', 'Building', 'Floor'])
('Building_id', ['Building_id']) ('Building', ['ResID', 'Building'])

所以这只是在建筑结构的不同层次上迭代

res = df2.groupby(remaining_ids)[label].first()

在结构中按级别生成一个数据帧,表示此级别的项,并将嵌套ID作为(多)索引添加到此级别。这是最终数据结构所需的信息,只需将其转换为嵌套的dict

Building_id  Floor_id
1            1                        Ground
             13          Secret/Hidden Floor
             2                       Balcony
             3                     Mezzanine
2            1                          Roof

到文本(无嵌套)

res.index = res.index.to_series().apply('.'.join)
print(res)
1.1                  Ground
1.13    Secret/Hidden Floor
1.2                 Balcony
1.3               Mezzanine
2.1                    Roof
Name: Floor, dtype: object

相关问题 更多 >