3

I am reading a cfg file, and receive a dictionary for each section. So, for example:

Config-File:

[General]
parameter1="Param1"
parameter2="Param2"

[FileList]
file001="file1.txt"
file002="file2.txt" ......

I have the FileList section stored in a dictionary called section. In this example, I can access "file1.txt" as test = section["file001"], so test == "file1.txt". To access every file of FileList one after the other, I could try the following:

for i in range(1, (number_of_files + 1)):
    access_key = str("file_00" + str(i))
    print(section[access_key])

This is my current solution, but I don't like it at all. First of all, it looks kind of messy in python, but I will also face problems when more than 9 files are listed in the config.

I could also do it like:

for i in range(1, (number_of_files + 1)):
    if (i <= 9):
        access_key = str("file_00" + str(i))
    elif (i > 9 and i < 100):
        access_key = str("file_0" + str(i))
    print(section[access_key])

But I don't want to start with that because it becomes even worse. So my question is: What would be a proper and relatively clean way to go through all the file names in order? I definitely need the loop because I need to perform some actions with every file.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
user44791
  • 37
  • 7

3 Answers3

2

Use zero padding to generate the file number (for e.g. see this SO question answer: https://stackoverflow.com/a/339013/3775361). That way you don’t have to write the logic of moving through digit rollover yourself—you can use built-in Python functionality to do it for you. If you’re using Python 3 I’d also recommend you try out f-strings (one of the suggested solutions at the link above). They’re awesome!

bob
  • 419
  • 4
  • 11
  • That's exactly what I was looking for, much more convenient. Thank you! – user44791 Apr 06 '22 at 12:37
  • This sounds wrong. You're still iterating 999 keys for a file containing 3. And you're liable to miss keys if the user misses a number or accidentally adds or skips a digit. – Mad Physicist Apr 06 '22 at 12:43
  • It depends on what OP intends to do. My answer takes at face value that OP really needs to iterate over the list of possible keys, and answers how to do so. I agree with your point but think that would be a separate question. – bob Apr 06 '22 at 13:24
1

If we can assume the file number has three digits, then you can do the followings to achieve zero padding. All of the below returns "015".

i = 15

str(i).zfill(3)
# or
"%03d" % i 
# or
"{:0>3}".format(i)
# or
f"{i:0>3}"
Kota Mori
  • 6,510
  • 1
  • 21
  • 25
  • Thanks for your solution, the answer in the link https://stackoverflow.com/a/339013/3775361 uses this method aswell – user44791 Apr 06 '22 at 12:38
0

Start by looking at the keys you actually have instead of guessing what they might be. You need to filter out the ones that match your pattern, and sort according to the numerical portion.

keys = [key for key in section.keys() if key.startswith('file') and key[4:].isdigit()]

You can add additional conditions, like len(key) > 4, or drop the conditions entirely. You might also consider learning regular expressions to make the checking more elegant.

To sort the names without having to account for padding, you can do something like

keys = sorted(keys, key=lambda s: int(s[4:]))

You can also try a library like natsort, which will handle the custom sort key much more generally.

Now you can iterate over the keys and do whatever you want:

for key in sorted((k for k in section if k.startswith('file') and k[4:].isdigit()), key=lambda s: int(s[4:])):
    print(section[key])

Here is what a solution equipt with re and natsort might look like:

import re
from natsort import natsorted

pattern = re.compile(r'file\d+')
for key in natsorted(k for k in section if pattern.fullmatch(k)):
    print(section[key])
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264