franvergara66 franvergara66 -4 years ago 118
Python Question

Generate a list of dictonary elements for files in folder

I am making a script that lists the existing files in a directory,and then save them to a dictionary list. In the directory there are two types of images .. "food" and "bar", which at the end of the name have an identifier to know the position in which they should be viewed, for example:


And I want to get the next result:

files = [ {'position': 1, 'foo': '/img/foo_1.jpg','bar': '/img/bar_1.jpg'},
{'position': 2, 'foo': '/img/foo_2.jpg','bar': '/img/bar_2.jpg'},
{'position': 3, 'foo': '','bar': '/img/bar_3.jpg',
{'position': 5, 'foo': '/img/foo_5.jpg','bar': ''} ]

There's my code:

def files_in_folder(folder_name):
folder_path = os.path.join(current_app.config['UPLOAD_FOLDER'], 'files', str(folder_name))
data = []
if not os.path.isdir(folder_path):
return [{}, {}, {}, {}, {}, {}, {}, {}, {}]
for filename in os.listdir(folder_path):
position = int('[0-9]+', filename).group())
if "foo" in filename:
foo_register = {'position': position,
'foo': folder_path + '/' + filename,
'bar': ''}
bar_register = {'position': position,
'foo': '',
'bar': folder_path + '/' + filename }
register = {**foo_register, **bar_register}
data.insert(position-1, register)

My result is:

[{'foo': '', 'bar': 'uploads/campaigns/1/bar_1.png', 'position': 1},
{'foo': '', 'bar': 'uploads/campaigns/1/bar_2.png', 'position': 2},
{'foo': '', 'bar': 'uploads/campaigns/1/bar_3.png', 'position': 3},
{'foo': 'uploads/campaigns/1/foo_1.png', 'bar': '', 'position': 1,
{'foo': '', 'bar': 'uploads/campaigns/1/bar_3.png', 'position': 3}]

What I'm missing in my code?. There's a best pythonic way to do this?

Thanks in advance.

Answer Source

Obviously, I don't have those files on my HD, so here's some code that processes a list of file names, but it shouldn't be hard to adapt it for your purposes.

The heart of this code is a helper function parse_name that extracts the position (pos) and image type info (kind) from a file name.

To organize that info the way you want I put it into a dict of dicts. We then sort the keys of the outer dict to create the desired list of dicts. We use a numeric sort so that 11 doesn't sort before 2, etc.

import os.path
from pprint import pprint

data = '''\

def parse_name(s):
    fname = os.path.basename(s)
    fbase, _ = os.path.splitext(fname)
    kind, pos = fbase.split('_')
    return kind, int(pos)

files_dict = {} 
for s in data:
    kind, pos = parse_name(s)
    d = files_dict.setdefault(pos, {'position': pos})
    d[kind] = s


files_list = [files_dict[k] for k in sorted(files_dict.keys(), key=int)]


{1: {'bar': '/img/bar_1.jpg', 'foo': '/img/foo_1.jpg', 'position': 1},
 2: {'bar': '/img/bar_2.jpg', 'foo': '/img/foo_2.jpg', 'position': 2},
 3: {'bar': '/img/bar_3.jpg', 'position': 3},
 5: {'foo': '/img/foo_5.jpg', 'position': 5}}

[{'bar': '/img/bar_1.jpg', 'foo': '/img/foo_1.jpg', 'position': 1},
 {'bar': '/img/bar_2.jpg', 'foo': '/img/foo_2.jpg', 'position': 2},
 {'bar': '/img/bar_3.jpg', 'position': 3},
 {'foo': '/img/foo_5.jpg', 'position': 5}]

Here's an alternative way to create files_list from files_dict:

files_list = sorted(files_dict.items(), key=lambda t: int(t[0]))

That for loop could be condensed to:

for s in data:
    kind, pos = parse_name(s)
    files_dict.setdefault(pos, {'position': pos})[kind] = s

although that's even more cryptic than the previous version. ;)

files_dict.setdefault(pos, {'position': pos})

fetches the sub-dict in files_dict with the key pos. If it doesn't exist, it's created with an initial key-value pair of ('position', pos).

We then update that sub-dict with the (kind, s), where s is the full filename of the the current file.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download