【问题标题】:Trying to avoid nested for loops尽量避免嵌套 for 循环
【发布时间】:2020-05-21 07:21:29
【问题描述】:

如何摆脱代码中的这些嵌套 for 循环?我曾尝试使用列表理解,但没有设法创造出任何好的东西。谢谢您的帮助!这是我的部分代码:

    folders = [i for i in range(1, int(number_of_folders) + 1)]
    subfolders = [i for i in range(1, int(number_of_subfolders) + 1)]
    files = [i for i in range(1, int(number_of_files) + 1)]        

    for i in folders:
        folderpath = path + "/folder-" + str(i)

        for j in subfolders:
            subfolderpath = folderpath + "/subfolder-" + str(j)
            os.makedirs(subfolderpath)

            for k in files:
                file_path = subfolderpath + "/files-" + str(j) + '-' + str(k) + ".txt"
                open(file_path, "w")

【问题讨论】:

  • 我评论说上面的代码相当清晰和高效。我要做的一个更改是使用生成器表达式,例如 folders = (i for i in range(1, int(number_of_folders) + 1) 或更好,但只需说 for i in range(1, int(number_of_folders) + 1) 并完全消除 folders 变量(主要是为了清晰和简洁)。但是对于 number_of_folders 的小值,它可能对效率的影响很小。

标签: python for-loop nested nested-loops


【解决方案1】:

首先你可以减少每个循环中的代码并用os.path.join整理:

for i in folders:
        for j in subfolders:
            subfolder_path = os.path.join(path, f"folder{i}", f"subfolder{j}")
            os.makedirs(subfolder_path)
            for k in files:
                file_path = os.path.join(subfolderpath, "files-{j}-{k}.txt")
                open(file_path, "w")

然后可以用itertools.product将前2个循环变成1个:

import itertools

for i,j in itertools.product(folders, subfolders):
    subfolder_path = os.path.join(path, f"folder{i}", f"subfolder{j}")
    os.makedirs(subfolder_path)
    for k in files:
         file_path = os.path.join(subfolderpath, "files-{j}-{k}.txt")
         open(file_path, "w")

但是如果文件路径不存在,如何创建一个函数来创建文件路径呢?然后我们可以压缩成一个for循环。

def open_and_create(folder_path, file_name, *a):
    os.makedirs(folder_path, exist_ok=True)
    return open(os.path.join(folder_path, file_name) *a)

for i,j,k in itertools.product(folders, subfolders, files):
    subfolder_path = os.path.join(path, f"folder{i}", f"subfolder{j}")
    open_and_create(subfolder_path, "files-{j}-{k}.txt", 'w')

【讨论】:

    【解决方案2】:

    以下代码使用list comprehensions 形成所有子文件夹和文件名:

    all_subfolders_list = [f"{path}/folder-{str(i)}/subfolder-{str(j)}/"
                      for i in range(1, int(number_of_folders) + 1)
                      for j in range(1, int(number_of_subfolders) + 1)]
    
    all_filenames = [f"{subfolder_path}{k}" for subfolder_path in all_subfolders_list
                     for k in range(1, int(number_of_files) + 1)]
    
    for subfolderpath in all_subfolders_list:
        os.makedirs(subfolderpath)
    
    for file_path in all_filenames:
        open(file_path, "w")
    

    【讨论】:

      【解决方案3】:

      我不确定您为什么要修改代码以使用列表推导,因为它相当清晰和高效。但是直接将您的代码转换为使用列表推导是:

      import os
      
      number_of_folders = 2
      number_of_subfolders = 3
      number_of_files = 4
      
      path = 'path'
      
      def create_dir_and_file(file_path, file_name):
            os.makdedirs(file_path, exist_ok=True)
            open(file_name, "w")
      
      [create_dir_and_file(f'{path}/folder-{i}/subfolder{j}', f'files{j}-{k}.txt')
            for i in range(1, int(number_of_folders) + 1)
            for j in range(1, int(number_of_subfolders) + 1)
            for k in range(1, int(number_of_files) + 1)]
      

      【讨论】:

      • 我还考虑过将所有逻辑“压缩”为单个列表理解。但是我得到了错误,因为在这种情况下程序会尝试创建每个子文件夹 number_of_files 次。
      • 好点。我修改了os.makedirs 以添加exist_ok=True 以在目录已存在时忽略错误。
      猜你喜欢
      • 2012-06-25
      • 2017-08-27
      • 2017-11-11
      • 2019-12-26
      • 1970-01-01
      • 2021-08-19
      • 2015-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多