【问题标题】:Python: finding files with matching extensions or extensions with matching names in a listPython:在列表中查找具有匹配扩展名或具有匹配名称的扩展名的文件
【发布时间】:2010-07-04 03:39:08
【问题描述】:

假设我有一个文件名列表:[exia.gundam, dynames.gundam, kyrios.gundam, virtue.gundam][exia.frame, exia.head, exia.swords, exia.legs, exia.arms, exia.pilot, exia.gn_drive, lockon_stratos.data, tieria_erde.data, ribbons_almark.data, otherstuff.dada]

在一次迭代中,我想拥有所有 *.gundam 或 *.data 文件,而在另一次迭代中,我想对 exia.* 文件进行分组。除了遍历列表并将每个元素放入字典之外,最简单的方法是什么?

这是我的想法:

def matching_names(files):
    '''
    extracts files with repeated names from a list

    Keyword arguments:
    files - list of filenames

    Returns: Dictionary
    '''

    nameDict = {}
    for file in files:
        filename = file.partition('.')
        if filename[0] not in nameDict:
            nameDict[filename[0]] = []
        nameDict[filename[0]].append(filename[2])

    matchingDict = {}
    for key in nameDict.keys():
        if len(nameDict[key]) > 1:
            matchingDict[key] = nameDict[key] 
    return matchingDict

好吧,假设我必须使用它,有没有一种简单的方法来反转它并将文件扩展名作为键而不是名称?

【问题讨论】:

    标签: python regex string


    【解决方案1】:

    在我的第一个版本中,我似乎误解了您的问题。因此,如果我的判断正确,您将尝试处理文件列表,以便您可以轻松访问具有给定扩展名的所有文件名,或具有给定基础的所有文件名(“基础”是前面的部分期间)?

    如果是这样的话,我会推荐这种方式:

    from itertools import groupby
    
    def group_by_name(filenames):
        '''Puts the filenames in the given iterable into a dictionary where
        the key is the first component of the filename and the value is
        a list of the filenames with that component.'''
        keyfunc = lambda f: f.split('.', 1)[0]
        return dict( (k, list(g)) for k,g in groupby(
                   sorted(filenames, key=keyfunc), key=keyfunc
               ) )
    

    例如,给定列表

    >>> test_data = [
    ...   exia.frame, exia.head, exia.swords, exia.legs,
    ...   exia.arms, exia.pilot, exia.gn_drive, lockon_stratos.data,
    ...   tieria_erde.data, ribbons_almark.data, otherstuff.dada
    ... ]
    

    那个函数会产生

    >>> group_by_name(test_data)
    {'exia': ['exia.arms', 'exia.frame', 'exia.gn_drive', 'exia.head',
              'exia.legs', 'exia.pilot', 'exia.swords'],
     'lockon_stratos': ['lockon_stratos.data'],
     'otherstuff': ['otherstuff.dada'],
     'ribbons_almark': ['ribbons_almark.data'],
     'tieria_erde': ['tieria_erde.data']}
    

    如果您想改为按扩展名索引文件名,只需稍作修改即可:

    def group_by_extension(filenames):
        '''Puts the filenames in the given iterable into a dictionary where
        the key is the last component of the filename and the value is
        a list of the filenames with that extension.'''
        keyfunc = lambda f: f.split('.', 1)[1]
        return dict( (k, list(g)) for k,g in groupby(
                   sorted(filenames, key=keyfunc), key=keyfunc
               ) )
    

    唯一的区别在于keyfunc = ... 行,我将密钥从 0 更改为 1。示例:

    >>> group_by_extension(test_data)
    {'arms': ['exia.arms'],
     'dada': ['otherstuff.dada'],
     'data': ['lockon_stratos.data', 'ribbons_almark.data', 'tieria_erde.data'],
     'frame': ['exia.frame'],
     'gn_drive': ['exia.gn_drive'],
     'head': ['exia.head'],
     'legs': ['exia.legs'],
     'pilot': ['exia.pilot'],
     'swords': ['exia.swords']}
    

    但是,如果您想同时获得这两个分组,我认为最好避免列表理解,因为这只能以一种或另一种方式处理它们,它不能构造两个不同的字典一次。

    from collections import defaultdict
    def group_by_both(filenames):
        '''Puts the filenames in the given iterable into two dictionaries,
        where in the first, the key is the first component of the filename,
        and in the second, the key is the last component of the filename.
        The values in each dictionary are lists of the filenames with that
        base or extension.'''
        by_name = defaultdict(list)
        by_ext = defaultdict(list)
        for f in filenames:
            name, ext = f.split('.', 1)
            by_name[name] += [f]
            by_ext[ext] += [f]
        return by_name, by_ext
    

    【讨论】:

    • 我可以遍历列表,但我想知道是否有更通用(和简单)的解决方案。因此,如果我要将格式从 .gundam 更改为 .flag,我可以使用相同的代码。我可以迭代列表并手动将它们添加到地图中,以查看根据文件名的第一部分或第二部分匹配的内容,但这会导致更多代码。
    • 好的,我想也许我在编辑版本中的最后一个代码示例更符合您的要求。如果所有条件都指定了文件名的开头或结尾,则可以使用startswithendswith 字符串方法而不是正则表达式,这可能会节省一些计算时间,但代码会更长(但如果你愿意,我也可以这样编辑)。
    • @Setsuna:好吧,我认为您可以使用 os.listdir(path) 遍历目录并获取所有可用的扩展,然后,您可以使用该列表将它们分组,就像 David 说的那样。跨度>
    • @Oscar Carballal 我用我对 Python 的了解/理解编辑了 OP,以显示我想要的,但更短。
    • @Setsuna:谢谢,这很有帮助。我会相应地编辑我的答案。
    【解决方案2】:

    我不确定我是否完全明白你想要做什么,但如果我理解正确的话,这样的事情可能会奏效:

    from collections import defaultdict
    files_by_extension = defaultdict(list)
    
    for f in files:
        files_by_extension[ f.split('.')[1] ].append(f)
    

    这是创建一个以文件扩展名为键的哈希,并通过一次遍历列表来填充它。

    【讨论】:

      【解决方案3】:

      例如,假设您希望得到一个文件名列表列表,按扩展名或根名分组:

      import os.path
      import itertools as it
      
      def files_grouped_by(filenames, use_extension=True):
          def ky(fn): return os.path.splitext(fn)[use_extension]
          return [list(g) for _, g in it.groupby(sorted(filenames, key=ky), ky)]
      

      现在files_grouped_by(filenames, False) 将返回按 rootname 分组的列表列表,而如果第二个参数为 True 或不存在,则分组将按扩展名。

      如果您想要一个 dict,键是根名称或扩展名,值是相应的文件名列表,方法非常相似:

      import os.path
      import itertools as it
      
      def dict_files_grouped_by(filenames, use_extension=True):
          def ky(fn): return os.path.splitext(fn)[use_extension]
          return dict((k, list(g)) 
                      for k, g in it.groupby(sorted(filenames, key=ky), ky)]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-10
        • 1970-01-01
        • 2011-03-13
        • 2021-07-09
        相关资源
        最近更新 更多