Python – Recursive Excel files to find top-level items from a tree structure

Recursive Excel files to find top-level items from a tree structure… here is a solution to the problem.

Recursive Excel files to find top-level items from a tree structure

I’m trying to recurse a dataset to find the highest level item, i.e. the item without a parent.

The structure is as follows:

╔════════════╦════════════╗
║    Item    ║  Material  ║
╠════════════╬════════════╣
║ 2094-00003 ║ MHY00007   ║
║ 2105-0001  ║ 2105-0002  ║
║ 2105-0002  ║ 2105-1000  ║
║ 2105-1000  ║ 2105-1003  ║
║ 2105-1003  ║ 7547-122   ║
║ 7932-00001 ║ 7932-00015 ║
║ 7932-00002 ║ 7932-00015 ║
║ 7932-00010 ║ MHY00007   ║
║ 7932-00015 ║ 7932-05000 ║
║ 7932-05000 ║ MHY00007   ║
╚════════════╩════════════╝

So, for example, if I select 7547-122, the function will return 2105-0001. So the function recursively goes up the tree, 7547-122 -> 2105-1003 -> 2105-1000 -> … -> 2105-0001.

When I run my code, I can only get it to return one top level, and as you can see from the MHY00007 case, sometimes there are multiple top layers. How can I return all the top lists for any given Material?

My code:

import pandas as pd

class BillOfMaterials:

def __init__(self, bom_excel_path):
        self.df = pd.read_excel(bom_excel_path)
        self.df = self.df[['Item', 'Material']]

def find_parents(self, part_number):
        material_parent_search = self.df[self.df.Material == part_number]

parents = list(set(material_parent_search['Item']))

return parents

def find_top_levels(self, parents):

top_levels = self.__ancestor_finder_([parents])

print(f'{parents} top level is {top_levels}')
        return {parents: top_levels}

def __ancestor_finder_(self, list_of_items):

for ancestor in list_of_items:
            print(f'Searching for ancestors of {ancestor}')
            ancestors = self.find_parents(ancestor)
            print(f'{ancestor} has ancestor(s) {ancestors}')

if not ancestors:
                return ancestor
            else:
                highest_level = self.__ancestor_finder_(ancestors)
        return highest_level

BOM = BillOfMaterials(bom_excel_path="Path/To/Excel/File/BOM.xlsx")

ItemsToSearch = ['7547-122', 'MHY00007']

top_levels = []
for item in ItemsToSearch:
    top_levels.append(BOM.find_top_levels(item))

Solution

Yes, you can do this recursively, for example:

import pandas as pd

class BillOfMaterials:

def __init__(self, bom_excel_path):
        self.df = pd.read_excel(bom_excel_path)
        self.df = self.df[['Item', 'Material']]

def find_parents(self, part_number):
        return list(set(self.df[self.df.Material == part_number]['Item']))

def find_top_levels(self, item):
        parents = self.find_parents(item)
        if not parents:
            # there are no parent items => this item is a leaf
            return [item]
        else:
            # there are parent items => recursively find grandparents
            grandparents = []
            for parent in parents:
                grandparents = grandparents + self.find_top_levels(parent)
            return grandparents

if __name__ == '__main__':
    BOM = BillOfMaterials(bom_excel_path="testdata.xlsx")
    ItemsToSearch = ['7547-122', 'MHY00007']

for i in ItemsToSearch:
        print('')
        print('The top levels of ' + i + ' are: ')
        print(BOM.find_top_levels(i))

Note the recursive call of self.find_top_levels (parent).
This will give the output

The top levels of 7547-122 are: 
['2105-0001']

The top levels of MHY00007 are: 
['2094-00003', '7932-00001', '7932-00002', '7932-00010']

Related Problems and Solutions