Home > Back-end >  convert the usual file.txt format into dictionaty format, nested dictionary python
convert the usual file.txt format into dictionaty format, nested dictionary python

Time:11-23

I am opening a cook-book 'recipes.txt' and it reads like this:

f = open('recipes.txt', 'r', encoding='utf-8')
for x in f:
    print(x)

result:

Omelet

3

Egg | 2 | PCS

Milk | 100 | ml

Tomato | 2 | PCS

Peking Duck

4

Duck | 1 | PCS

Water | 2 | l

Honey | 3 | t.sp

Soy sauce | 60 | ml

I need to read / convert it into a nested dictionary format, like this:

cook_book = {


 'Omelet': [
    {'ingredient_name': 'Egg', 'quantity': 2, 'measure': 'PCS'},
    {'ingredient_name': 'Milk', 'quantity': 100, 'measure': 'ml'},
    {'ingredient_name': 'Tomato', 'quantity': 2, 'measure': 'PCS'}
    ],
  'Peking Duck': [
    {'ingredient_name': 'Duck', 'quantity': 1, 'measure': 'PCS'},
    {'ingredient_name': 'Water', 'quantity': 2, 'measure': 'l'},
    {'ingredient_name': 'Honey', 'quantity': 3, 'measure': 't.sp'},
    {'ingredient_name': 'Soy sauce', 'quantity': 60, 'measure': 'ml'}
    ]
    }

I cannot get on my own how to get exactly desired format. Would appreciate any suggestions.

CodePudding user response:

Hey maybe a little shorter then @Hunters solution

with open('recipes.txt', 'r', encoding='utf-8') as recipes:
    cook_book = {}
    for line in recipes:
        if  (line.replace("\n", "")).isnumeric() or line == "\n":   # Ignore unwanted lines
            continue
        elif "|" not in line:   # Initialize individual recipes
            current_recipe = line.replace("\n", "")
            cook_book[current_recipe] = []
        elif len(line.strip("|")) > 2:  # Add ingredients
            ingredient = {}
            ingredient_lst = line.split("|")
            ingredient["ingredient_name"] = ingredient_lst[0].strip()
            ingredient["quantity"] = ingredient_lst[1].strip()
            ingredient["measure"] = ingredient_lst[2].replace("\n", "").strip()

            cook_book[current_recipe].append(ingredient)

print(cook_book)

If u load any file and read from it you should always use a with block - python will then handle closing the file etc on its own.

EDIT:

If you want to dump the cook_book to a json file you could add this

import json

with open('cook_book.json', 'w', encoding='utf-8') as f:
    json.dump(cook_book, f, ensure_ascii=False, indent=4)

Results in this:

{
    "Omelet": [
        {
            "ingredient_name": "Egg ",
            "quantity": " 2 ",
            "measure": " PCS"
        },
        {
            "ingredient_name": "Milk ",
            "quantity": " 100 ",
            "measure": " ml"
        },
        {
            "ingredient_name": "Tomato ",
            "quantity": " 2 ",
            "measure": " PCS"
        }
    ],
    "Peking Duck": [
        {
            "ingredient_name": "Duck ",
            "quantity": " 1 ",
            "measure": " PCS"
        },
        {
            "ingredient_name": "Water ",
            "quantity": " 2 ",
            "measure": " l"
        },
        {
            "ingredient_name": "Honey ",
            "quantity": " 3 ",
            "measure": " t.sp"
        },
        {
            "ingredient_name": "Soy sauce ",
            "quantity": " 60 ",
            "measure": " ml"
        }
    ]
}

CodePudding user response:

What you have done is just read from the file, whereas you should be taking values from it and assigning it within the dictionaries.

cook_book = {}

indexes = []

with open('recipes.txt', 'r', encoding='utf-8') as fp:
    data = fp.read()
    linedData = data.split('\n')
    i = 0
    for line in data.split('\n'):
        try:
            amount = int(line)
            indexes.append(i)
            indexes.append(amount)
        except:
            pass
        i  = 1
    for x in range(len(indexes)):
        if (x % 2) == 0:
            mealName = linedData[indexes[x]-1]
            focusedData = linedData[indexes[x]   1:]
            focusedData = focusedData[:(indexes[x 1])]
            totalIngredients = []
            for line in focusedData:
                ingredients = {}
                try:
                    name, amm, ref = line.split(' | ')
                    ingredients['ingredient_name'] = name
                    ingredients['quantity'] = int(amm)
                    ingredients['measure'] = ref
                except:
                    pass
                totalIngredients.append(ingredients)
            cook_book[mealName] = totalIngredients

    print(cook_book)

creates an output of:

{'Omelette': [{'ingredient_name': 'Egg', 'quantity': 2, 'measure': 'PCS'}, {'ingredient_name': 'Milk', 'quantity': 100, 'measure': 'ml'}, {'ingredient_name': 'Tomato', 'quantity': 2, 'measure': 'PCS'}], 'Peking duck': [{'ingredient_name': 'Duck', 'quantity': 1, 'measure': 'PCS'}, {'ingredient_name': 'Water', 'quantity': 2, 'measure': 'l'}, {'ingredient_name': 'Honey', 'quantity': 3, 'measure': 'tbsp'}, {'ingredient_name': 'Soy sauce', 'quantity': 60, 'measure': 'ml'}], 'Baked potatoes': [{'ingredient_name': 'Potatoes', 'quantity': 1, 'measure': 'kg'}, {'ingredient_name': 'Garlic', 'quantity': 3, 'measure': 'tooth'}, {'ingredient_name': 'Gouda cheese', 'quantity': 100, 'measure': 'G'}], 'Fajitos': [{'ingredient_name': 'Beef', 'quantity': 500, 'measure': 'G'}, {'ingredient_name': 'Sweet pepper', 'quantity': 1, 'measure': 'PCS'}, {'ingredient_name': 'Lavash', 'quantity': 2, 'measure': 'state'}, {'ingredient_name': 'Wine vinegar', 'quantity': 1, 'measure': 'tbsp'}, {'ingredient_name': 'Tomato', 'quantity': 2, 'measure': 'state'}]}

But when formatted it creates your desired output of:

{
'Omelette': [
    {'ingredient_name': 'Egg', 'quantity': 2, 'measure': 'PCS'}, 
    {'ingredient_name': 'Milk', 'quantity': 100, 'measure': 'ml'}, 
    {'ingredient_name': 'Tomato', 'quantity': 2, 'measure': 'PCS'}
    ],
'Peking duck': [
    {'ingredient_name': 'Duck', 'quantity': 1, 'measure': 'PCS'}, 
    {'ingredient_name': 'Water', 'quantity': 2, 'measure': 'l'}, 
    {'ingredient_name': 'Honey', 'quantity': 3, 'measure': 'tbsp'}, 
    {'ingredient_name': 'Soy sauce', 'quantity': 60, 'measure': 'ml'}
    ], 
'Baked potatoes': [
    {'ingredient_name': 'Potatoes', 'quantity': 1, 'measure': 'kg'}, 
    {'ingredient_name': 'Garlic', 'quantity': 3, 'measure': 'tooth'}, 
    {'ingredient_name': 'Gouda cheese', 'quantity': 100, 'measure': 'G'}
    ], 
'Fajitos': [
    {'ingredient_name': 'Beef', 'quantity': 500, 'measure': 'G'}, 
    {'ingredient_name': 'Sweet pepper', 'quantity': 1, 'measure': 'PCS'}, 
    {'ingredient_name': 'Lavash', 'quantity': 2, 'measure': 'state'}, 
    {'ingredient_name': 'Wine vinegar', 'quantity': 1, 'measure': 'tbsp'}, 
    {'ingredient_name': 'Tomato', 'quantity': 2, 'measure': 'state'}
    ]
}

Please bear in mind there are probably more efficient ways of achieving the desired output, and there will be ways to refactor my code, but this is my attempt at the question.

Hope this helps.

  • Related