简体   繁体   English

如何根据 Python 中类似定位的字符/模式对文件进行分组?

[英]How to group files based on similarly positioned characters/pattern in Python?

I have a set of file names in a list in different folders as shown below:我在不同文件夹的列表中有一组文件名,如下所示:

Input files输入文件

['ABC.dat',
'ABC10.dat',
'ABC956.dat',
'ABC_DEF_1.dat',
'ABC_DEF_2.dat',
'ABC_DEF_3.dat',
'ABC10_DEF_1.dat',
'ABC10_DEF_2.dat',
'ABC10_DEF_3.dat',
'ABC956_DEF_1.dat',
'ABC956_DEF_2.dat',
'ABC956_DEF_3.dat',
'XYZ_ABC_1.dat',
'XYZ_ABC_2.dat',
'XYZ10_ABC_1.dat',
'XYZ10_ABC_2.dat',
'XYZ956_ABC_1.dat',
'XYZ956_ABC_2.dat',
'XYZ_PQR_JKL.dat',
'XYZ_PQR_JKL_1.dat',
'XYZ_PQR10_JKL.dat',
'XYZ_PQR10_JKL_1.dat',
'XYZ_PQR956_JKL.dat',
'XYZ_PQR956_JKL_1.dat'] 

I would like to group the files as follows:我想按如下方式对文件进行分组:

Output list输出列表

[['ABC.dat', 'ABC10.dat', 'ABC956.dat'],
['ABC_DEF_1.dat', 'ABC10_DEF_1.dat.dat', 'ABC956_DEF_1.dat'],
['ABC_DEF_2.dat', 'ABC10_DEF_2.dat.dat', 'ABC956_DEF_2.dat'],
['ABC_DEF_3.dat', 'ABC10_DEF_3.dat.dat', 'ABC956_DEF_3.dat'],
['XYZ_ABC_1.dat', 'XYZ10_ABC_1.dat', 'XYZ956_ABC_1.dat'],
['XYZ_ABC_2.dat', 'XYZ10_ABC_2.dat', 'XYZ956_ABC_2.dat'],
['XYZ_PQR_JKL.dat', 'XYZ_PQR10_JKL.dat', 'XYZ_PQR956_JKL.dat'],
['XYZ_PQR_JKL_1.dat', 'XYZ_PQR10_JKL_1.dat', 'XYZ_PQR956_JKL_1.dat']]

That is to say the files should be grouped based on the pattern of files.也就是说,文件应该根据文件的模式进行分组。 Note DEF_1 and DEF_2 have to be grouped separately.注意 DEF_1 和 DEF_2 必须分开分组。 The numbers 10, 956 are random, ie, they are not known before hand.数字 10、956 是随机的,即它们是事先未知的。 A MWE is given below, which groups based on first few letters as obtained from OP , how can I extend it to the other letters that is DEF.下面给出了一个 MWE,它根据从OP获得的前几个字母进行分组,我如何将其扩展到 DEF 的其他字母。

MWE移动电源

import os
import random
import errno
import itertools
from itertools import repeat

#--------------------------------------
# Main rename code
for root, dirs, files in os.walk('./input_folder'):
    for dir in dirs: 
        print (dir)
        output_files = [s for s in os.listdir(os.path.join(root,dir)) if s.endswith('.dat')]
        groups =  [list(g) for _, g in itertools.groupby(sorted(output_files), lambda x: x[0:2])]    # obtained from Aaron's answer https://gis.stackexchange.com/a/206053
        print (groups)

You can use recursion:您可以使用递归:

import re
def is_match(a, b):
  a, b = re.sub('\s\w+\.dat$', '', a).split(), re.sub('\s\w+\.dat$', '', b).split()
  if len(a) != len(b):
     return False
  return all(c == d if not c.isdigit() and not d.isdigit() else c.isdigit() and d.isdigit() for c, d in zip(a, b))

def group_vals(d, _current = []):
  if _current:
    yield _current
  if d:
    _start, *_d = d
    yield from group_vals([i for i in _d if not is_match(_start, i)], [_start, *[i for i in _d if is_match(_start, i)]])

files = list(filter(None, _input.split('\n')))
print(list(group_vals(files)))

Output:输出:

[['ABC 956.dat', 'ABC 114.dat', 'ABC 577.dat', 'ABC 782.dat'], 
 ['ABC DEF 10.dat', 'ABC DEF 23.dat', 'ABC DEF 27.dat', 'ABC DEF 54.dat'], 
  ['XYZ-ABC 158.dat', 'XYZ-ABC 221.dat', 'XYZ-ABC 668.dat', 'XYZ-ABC 919.dat'], 
  ['ABC 127 JKL.dat', 'ABC 272 JKL.dat', 'ABC 462 JKL.dat', 'ABC 707 JKL.dat'], 
  ['ABC 137 XYZ 97.dat', 'ABC 164 XYZ 25.dat', 'ABC 418 XYZ 13.dat', 'ABC 913 XYZ 11.dat'], 
  ['ABC 258 PQR0 0.dat', 'ABC 551 PQR0 3.dat', 'ABC 606 PQR0 5.dat', 'ABC 654 PQR0 2.dat'], 
  ['ABC 542 PQR1 4.dat', 'ABC 234 PQR1 2.dat', 'ABC 432 PQR1 7.dat', 'ABC 766 PQR1 5.dat']]

You probably should try Regular Expression in Python (re library).您可能应该在 Python(重新库)中尝试正则表达式。

re.findall (pattern, string, flags=0) re.findall (模式,字符串,标志= 0)
Return all non-overlapping matches of pattern in string, as a list of strings.以字符串列表的形式返回字符串中模式的所有非重叠匹配项。

# suppose files is a string holds all your file names (you could join your file names together)
files = """ABC 956.dat
ABC DEF 10.dat
ABC DEF 23.dat
ABC DEF 27.dat
ABC DEF 54.dat
XYZ-ABC 158.dat
XYZ-ABC 221.dat
XYZ-ABC 668.dat
XYZ-ABC 919.dat"""

# use re to find the names with certain pattern.
import re
g1 = re.findall('ABC \d{3}.dat', files)
# ['ABC 956.dat', 'ABC 158.dat', 'ABC 221.dat', 'ABC 668.dat', 'ABC 919.dat']
g2 = re.findall('ABC DEF \d{2}.dat', files)
# ['ABC DEF 10.dat', 'ABC DEF 23.dat', 'ABC DEF 27.dat', 'ABC DEF 54.dat']

# more groups to go with similar settings

In the code example, \\d represents one digit and {n} represents the number of occurrence of the previous pattern.在代码示例中,\\d 表示一位,{n} 表示前一个模式出现的次数。 Thus \\d{3} means 3 digits.因此 \\d{3} 表示 3 位数字。

You could get more information about regular expression here .您可以在此处获得有关正则表达式的更多信息。

This is based on Ajax1234's answer.这是基于 Ajax1234 的回答。 It avoids that answer's redundant computation.它避免了该答案的冗余计算。 Rather than doing a recursive partition by an equivalence relation.而不是通过等价关系进行递归分区。 This does discrimination.这就是歧视。 This reduces the cost from N**2/2 calls to is_match to only N calls to key .这将成本从N**2/2调用is_match到仅N调用key key uses None as a wildcard for the parts of the filename that are digits. key使用None作为文件名中数字部分的通配符。

import re
from collections import defaultdict

def key(v):
    return tuple(None if p.isdigit() else p for p in re.sub('.dat$', '', v).split())

def partition(l, key=None):
    d = defaultdict(list)
    for e in l:
        k = key(e) if key is not None else e
        d[k].append(e)
    return [d[k] for k in sorted(d)]

partition(filter(None, _input.split('\n')), key=key)

This results in:这导致:

[['ABC 956.dat', 'ABC 114.dat', 'ABC 577.dat', 'ABC 782.dat'],
 ['ABC 127 JKL.dat', 'ABC 272 JKL.dat', 'ABC 462 JKL.dat', 'ABC 707 JKL.dat'],
 ['ABC 258 PQR0 0.dat', 'ABC 551 PQR0 3.dat', 'ABC 606 PQR0 5.dat', 'ABC 654 PQR0 2.dat'],
 ['ABC 542 PQR1 4.dat', 'ABC 234 PQR1 2.dat', 'ABC 432 PQR1 7.dat', 'ABC 766 PQR1 5.dat'],
 ['ABC 137 XYZ 97.dat', 'ABC 164 XYZ 25.dat', 'ABC 418 XYZ 13.dat', 'ABC 913 XYZ 11.dat'],
 ['ABC DEF 10.dat', 'ABC DEF 23.dat', 'ABC DEF 27.dat', 'ABC DEF 54.dat'],
 ['XYZ-ABC 158.dat', 'XYZ-ABC 221.dat', 'XYZ-ABC 668.dat', 'XYZ-ABC 919.dat']]

It seems I wasn't clear enough on where to make the changes:似乎我对在哪里进行更改还不够清楚:

def key(v):
    return tuple(None if p.isdigit() else p for p in re.sub('.dat$', '', v).split('_'))

partition(filter(None, input_list), key=key)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在python中将列表中名称相似的元素分组为元组? - How to group similarly named elements in a list into tuples in python? python 基于模式将文本文件中的行组拆分为单独的文件 - python splitting group of lines in text file in sparate files based on pattern Python on Windows:如何将 wxPython 中的小部件封装到标记组,类似于<fieldset>在 HTML 中?</fieldset> - Python on Windows: How to enclose widgets in wxPython to labelled group, similarly to <fieldset> in HTML? 根据模式识别一组文件和进程:Python - Identify a group of file and process based on a pattern : Python 用于在python中对不相关但类似形状的类进行子类型化的模式 - Pattern for subtyping unrelated but similarly-shaped classes in python 如何根据 Python 中的字符串值将文件分组为一行? - How to group the files in a single line based on a string value in Python? 如何排除 python 中的字符组 - How to exclude group of characters in python 如何检索名称相同的csv文件并使用它们创建数据框 - How to retrieve similarly named csv files and create dataframes with them 如何根据特殊字符过滤 csv 文件? - How to filter a csv files based on special characters? 如何用Python中的字符串替换一组或一组字符 - How to replace set or group of characters with string in Python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM