0

So I have a text file that looks something like this:

Monstera Deliciosa
2018-11-03 18:21:26
Tropical/sub-Tropical plant
Leathery leaves, mid to dark green
Moist and well-draining soil
Semi-shade/full shade light requirements
Water only when top 2 inches of soil is dry
Intolerant to root rot
Propagate by cuttings in water

Strelitzia Nicolai (White Birds of Paradise)
2018-11-05 10:12:15
Semi-shade, full sun
Dark green leathery leaves
Like lots of water,but soil cannot be water-logged
Like to be root bound in pot

Alocasia Macrorrhizos
2019-01-03 15:29:10
Tropical asia
Moist and well-draining soil
Leaves and stem toxic upon ingestion
Semi-shade, full sun
Like lots of water, less susceptible to root rot
Susceptible to spider mites

I want to create a dictionary out of this file with the names of the plants to be the key of the dictionary and the rest of the info be put in a list as the values. So far I've managed to get each plant and its respective info as an item in a list but i'm not sure how to transform it to a dictionary.

    with open('myplants.txt', 'r') as f:
        contents = f.read()
        contents = contents.rstrip().split('\n\n')
        contents = [x.replace('\n', ', ') for x in contents]
    print(contents)#[0].split(',',0)[0])

Expected output:

plants = {'Monstera Deliciosa':['2018-11-03 18:21:26', 'Tropical/sub-Tropical plant', 'Leathery leaves, mid to dark green', 'Moist and well-draining soil', 'Semi-shade/full shade light requirements', 'Water only when top 2 inches of soil is dry', 'Intolerant to root rot', 'Propagate by cuttings in water'], 'Strelitzia Nicolai (White Birds of Paradise)': ... }

I am open to better formats on how the dictionary should look like.

Aaron
  • 165
  • 8

4 Answers4

1

Here's a scalable solution that avoids reading the whole file in memory.

It makes use of the fact that a text file can be used as an iterator yielding each line

import itertools as it

plants = {}
with open('myplants.txt') as f:
    while True:
        try:
            p = next(f).rstrip()
            plants[p] = list(l.rstrip() for l in it.takewhile(lambda line: line != '\n', f))
        except StopIteration:
            break

print(plants)

produces

{
 'Monstera Deliciosa': ['2018-11-03 18:21:26', 'Tropical/sub-Tropical plant', 'Leathery leaves, mid to dark green', 'Moist and well-draining soil', 'Semi-shade/full shade light requirements', 'Water only when top 2 inches of soil is dry', 'Intolerant to root rot', 'Propagate by cuttings in water'],
 'Strelitzia Nicolai (White Birds of Paradise)': ['2018-11-05 10:12:15', 'Semi-shade, full sun', 'Dark green leathery leaves', 'Like lots of water,but soil cannot be water-logged', 'Like to be root bound in pot'],
 'Alocasia Macrorrhizos': ['2019-01-03 15:29:10', 'Tropical asia', 'Moist and well-draining soil', 'Leaves and stem toxic upon ingestion', 'Semi-shade, full sun', 'Like lots of water, less susceptible to root rot', 'Susceptible to spider mites']
}
Pynchia
  • 10,996
  • 5
  • 34
  • 43
0

Use a dictionary comprehension:

text = """Monstera Deliciosa
2018-11-03 18:21:26
Tropical/sub-Tropical plant
Leathery leaves, mid to dark green
Moist and well-draining soil
Semi-shade/full shade light requirements
Water only when top 2 inches of soil is dry
Intolerant to root rot
Propagate by cuttings in water

Strelitzia Nicolai (White Birds of Paradise)
2018-11-05 10:12:15
Semi-shade, full sun
Dark green leathery leaves
Like lots of water,but soil cannot be water-logged
Like to be root bound in pot

Alocasia Macrorrhizos
2019-01-03 15:29:10
Tropical asia
Moist and well-draining soil
Leaves and stem toxic upon ingestion
Semi-shade, full sun
Like lots of water, less susceptible to root rot
Susceptible to spider mites
"""

contents = text.rstrip().split('\n\n')
contents = [x.replace('\n', ', ') for x in contents]

plants = {c.split(',')[0]: c.split(',')[1:]
          for c in contents}

print(plants)

Returning:

{'Monstera Deliciosa': [' 2018-11-03 18:21:26', ' Tropical/sub-Tropical plant', ' Leathery leaves', ' mid to dark green', ' Moist and well-draining soil', ' Semi-shade/full shade light requirements', ' Water only when top 2 inches of soil is dry', ' Intolerant to root rot', ' Propagate by cuttings in water'], 'Strelitzia Nicolai (White Birds of Paradise)': [' 2018-11-05 10:12:15', ' Semi-shade', ' full sun', ' Dark green leathery leaves', ' Like lots of water', 'but soil cannot be water-logged', ' Like to be root bound in pot'], 'Alocasia Macrorrhizos': [' 2019-01-03 15:29:10', ' Tropical asia', ' Moist and well-draining soil', ' Leaves and stem toxic upon ingestion', ' Semi-shade', ' full sun', ' Like lots of water', ' less susceptible to root rot', ' Susceptible to spider mites']}
Gustav Rasmussen
  • 3,720
  • 4
  • 23
  • 53
0

Will something like this work?

plants = {}
with open('myplants.txt', 'r') as f:
    contents = f.read()
    contents = contents.rstrip().split('\n\n')
    for content in contents:
      parts = content.split('\n') # Convert the lines to a list of strings
      plants[ parts[0] ] = parts[1:] # first line becomes key, the rest become the values
print(plants)
Shadab
  • 1,297
  • 6
  • 9
  • It works for files that fit in your system's available memory. Reading the whole contents in memory is highly discouraged and unnecessary – Pynchia Aug 13 '20 at 07:25
0

Here's a way to parse the data using states:

def parse(lines):
    items = []
    state = "name"

    for line in lines:
        line = line.rstrip("\n")

        if line == "":
            state = "name"
            continue

        if state == "name":
            item = {"name": line, "date": None, "data": []}
            items.append(item)
            state = "date"
            continue

        if state == "date":
            item["date"] = line
            state = "data"
            continue

        if state == "data":
            item["data"].append(line)
            continue

    return items

Which results in:

[{'name': 'Monstera Deliciosa',
  'date': '2018-11-03 18:21:26',
  'data': ['Tropical/sub-Tropical plant',
           'Leathery leaves, mid to dark green',
           'Moist and well-draining soil',
           'Semi-shade/full shade light requirements',
           'Water only when top 2 inches of soil is dry',
           'Intolerant to root rot',
           'Propagate by cuttings in water']},
 {'name': 'Strelitzia Nicolai (White Birds of Paradise)',
  'date': '2018-11-05 10:12:15',
  'data': ['Semi-shade, full sun',
           'Dark green leathery leaves',
           'Like lots of water,but soil cannot be water-logged',
           'Like to be root bound in pot']},
 {'name': 'Alocasia Macrorrhizos',
  'date': '2019-01-03 15:29:10',
  'data': ['Tropical asia',
           'Moist and well-draining soil',
           'Leaves and stem toxic upon ingestion',
           'Semi-shade, full sun',
           'Like lots of water, less susceptible to root rot',
           'Susceptible to spider mites']}]

I think this alternate representation is a bit nicer to work with.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135