【问题标题】:Python - Hierarchical relationship between lines in a CSVPython - CSV中行之间的层次关系
【发布时间】:2020-04-25 19:28:19
【问题描述】:

我正在使用一个包含数据的text 文件,我想以不同的形状重新组织它。该文件包含带值的行,用分号分隔,没有标题。某些行包含的值是其他行的子项。我可以用代码(1 或 2)和它们的顺序来区分它们:子值总是在父值之后的行中。一行与另一行之间的子元素数量不同。父值不能有子值。

更明确地说,这是一个数据示例:

030;001;1;AD0192;
030;001;2;AF5612;AF5613;AF5614
030;001;1;CD0124;
030;001;2;CD0846;CD0847;CD0848
030;002;1;EG0376;
030;002;2;EG0666;EG0667;EG0668;EG0669;EG0670;
030;003;1;ZB0001;
030;003;1;ZB0002;
030;003;1;ZB0003;
030;003;2;ZB0004;ZB0005

结构是:

  • 前三个字符是一个 id
  • 接下来的三个字符也是一个 id
  • 下一个是代码:当为 1 时,值(在我的示例中命名为键)是父级,当 2 个值是前一行的子级时。
  • 后面的值为键、父或子。

我想将子值(使用代码 2)存储在列表中,并在其父值的同一行中。

这是我上面的数据示例和标题的示例:

id1;id2;key;children;
030;001;AD0192;[AF5612,AF5613,AF5614]    
030;001;CD0124;[CD0846,CD0847,CD0848]
030;002;EG0376;[EG0666,EG0667,EG0668,EG0669,EG0670]    
030;003;ZB0001;
030;003;ZB0002;
030;003;ZB0003;[ZB0004,ZB0005]

我可以从这个text 源文件构建CSV 分隔文件,添加一个标题,一个DictReader 来轻松操纵我的列和条件来识别我的父母和孩子的价值观。

但是如何将分层元素(代码为 2)存储在其父键同一行的列表中?

这是我在Python中的实际脚本

import csv   

inputTextFile = 'myOriginalFile.txt'
csvFile = 'myNewFile.csv'
countKey = 0
countKeyParent = 0
countKeyChildren = 0

with open(inputTextFile, 'r', encoding='utf-8') as inputFile:
    stripped = (line.strip() for line in inputFile)    
    lines = (line.split(";") for line in stripped if line)        

    # Write a CSV file
    with open(csvFile, 'w', newline='', encoding='utf-8') as outputCsvFile:        
        writer = csv.writer(outputCsvFile, delimiter=';')
        writer.writerow(('id1','id2', 'code', 'key', 'children'))
        writer.writerows(lines)

# Read the CSV      
with open(csvFile, 'r', newline='', encoding='utf-8') as myCsvFile:
    csvReader = csv.DictReader(myCsvFile, delimiter=';', quotechar='"')

    for row in csvReader:
        countKey +=1        

        if '1' in row['code'] :
            countKeyParent += 1            
            print("Parent: " + row['key'])

        elif '2' in row['code'] :
            countKeyChildren += 1
            print("Children: " + row['key'])  

print(f"----\nSum of elements: {countKey}\nParents keys: {countKeyParent}\nChildren keys: {countKeyChildren}")

【问题讨论】:

    标签: python csv


    【解决方案1】:

    一个简单的解决方案可能如下。我首先将您的数据作为行列表加载,每个行都是字符串列表。然后,我们首先构建您解释的层次结构,并将输出写入 CSV 文件。

    from typing import List
    
    ID_FIRST = 0
    ID_SECOND = 1
    PARENT_FIELD = 2
    KEY_FIELD = 3
    
    IS_PARENT = "1"
    IS_CHILDREN = "2"
    
    
    def read(where: str) -> List[List[str]]:
        with open(where) as fp:
            data = fp.readlines()
    
        rows = []
    
        for line in data:
            fields = line.strip().split(';')
            rows.append([fields[ID_FIRST],
                         fields[ID_SECOND],
                         fields[PARENT_FIELD],
                         *[item for item in fields[KEY_FIELD:]
                           if item != ""]])
    
        return rows
    
    
    def assign_parents(rows: List[List[str]]):
        parent_idx = 0
    
        for idx, fields in enumerate(rows):
            if fields[PARENT_FIELD] == IS_PARENT:
                parent_idx = idx
    
            if fields[PARENT_FIELD] == IS_CHILDREN:
                rows[parent_idx] += fields[KEY_FIELD:]
    
    
    def write(where: str, rows: List[List[str]]):
        with open(where, 'w') as file:
            file.write("id1;id2;key;children;\n")
    
            for fields in rows:
                if fields[PARENT_FIELD] == IS_CHILDREN:
                    # These have been grouped into their parents.
                    continue
    
                string = ";".join(fields[:PARENT_FIELD])
                string += ";" + fields[KEY_FIELD] + ";"
    
                if len(fields[KEY_FIELD + 1:]) != 0:  # has children?
                    children = ",".join(fields[KEY_FIELD + 1:])
                    string += "[" + children + "]"
    
                file.write(string + '\n')
    
    
    def main():
        rows = read('myOriginalFile.txt')
    
        assign_parents(rows)
    
        write('myNewFile.csv', rows)
    
    
    if __name__ == "__main__":
        main()
    

    你的例子我得到

    id1;id2;key;children;
    030;001;AD0192;[AF5612,AF5613,AF5614]
    030;001;CD0124;[CD0846,CD0847,CD0848]
    030;002;EG0376;[EG0666,EG0667,EG0668,EG0669,EG0670]
    030;003;ZB0001;
    030;003;ZB0002;
    030;003;ZB0003;[ZB0004,ZB0005]
    

    这似乎是正确的。

    【讨论】:

      猜你喜欢
      • 2014-04-07
      • 2020-12-07
      • 2020-11-28
      • 1970-01-01
      • 2014-04-12
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      相关资源
      最近更新 更多