【问题标题】:Sort, group and process files based on an embedded timestamp in the filename [closed]根据文件名中嵌入的时间戳对文件进行排序、分组和处理[关闭]
【发布时间】:2021-09-27 04:54:49
【问题描述】:

如何按每个文件名中嵌入的日期字符串对这些文件进行排序?然后我想循环遍历同一天创建的所有文件。

我可以在 shell 中执行此操作,但速度很慢。我想在 python 中做同样的事情。

示例文件列表(共2200个文件)

  1. Tyler Cowen On Reading 202109200657.md
  2. 论诗 202109210659.md
  3. Slava Akhmechet 论集群阅读 202109200659.md
  4. 4X4 矩阵中的构思 202109200717.md
  5. 绘制网格构思 202109220830.md
  6. 听写201208251425.md

输出将如下所示(用于最终使用 Plotly 绘制图形。)

20120825,1  
20210920,3  
20210921,1  
20210922,1  

我想在给定日期按文档计数排序,然后按日期在文档计数内排序。因此上面的结果 1、3 和 4 将按日期顺序列出:

20210920,3
20120825,1  
20210921,1  
20210922,1  

然后我想对每天的文档做其他事情,比如获取当天的总字数。

【问题讨论】:

  • 诚实地尝试自己解决问题,并edit您的帖子通过minimal reproducible example提出具体问题如果你遇到问题。 Stack Overflow 不是免费的在线编码服务,“为我实现这个功能”在这里是off-topic
  • 欢迎来到 StackOverflow。你自己试过什么?你具体遇到了什么问题?分享您的一些工作并专注于特定问题,SO 将能够提供帮助。 stackoverflow.com/help/how-to-ask
  • 您可以分享您现有的 shell 脚本——这将帮助我们了解您的需求

标签: python loops sorting unique


【解决方案1】:

如果您尝试替换 shell 脚本,您的 Python 脚本可能需要执行以下操作。

  1. 列出目录的内容以获取文件名。
  2. 从文件名中提取日期(假设\d{8} 的正则表达式模式匹配足以提取日期)。
  3. 按提取日期对文件进行排序或分组。
  4. 遍历这些组以做某事。
import pathlib
import re
from collections import defaultdict

date_pattern = re.compile(r"\d{8}")
target_dir = pathlib.Path("myfolder")

# Files is a dictionary mapping a date to the list of files with that date
files = defaultdict(list)
for child in target_dir.iterdir():
    # Skip directories
    if child.is_dir():
        continue
    match = date_pattern.search(child.name)
    # Skip files that do not match the date pattern
    if match is None:
        continue
    file_date = match.group()
    files[file_date].append(child)

for date, names in files.items():
    for filename in names:
        # Do something
        print(date, filename)

编辑:按日期排序

要按日期排序,可以修改最后一个代码块。

for date in sorted(files):
    for filename in files[date]:
        # Do something
        print(date, filename)

你也可以使用for date, names in sorted(files.items(), key=lambda d: d[0]):

【讨论】:

  • 您的解决方案对我来说是最容易理解的。它运行迅速,但不按 date_pattern 对结果进行排序。
  • @WillSimpson,我添加了如何按日期对结果进行排序。
  • 按时间排序,而不是按日期排序,因此它不会计算或分组同一天的文档。这显然是 OP 中的要求
  • @Nick 在我的测试中,它按日期排序。正则表达式模式仅匹配时间戳的日期部分。
  • @ogdenkev 我明白你的意思。我的坏:)
【解决方案2】:

这是你需要的吗?以下代码从每个文件中提取日期并将其附加到以日期为键的字典中,因此您的字典将采用以下格式:

{
date1: [list of files],
date2: [list of files]
}

代码如下:

from collections import defaultdict
import re
files = ['Tyler Cowen On Reading 202109200657.md',
'On Poems 202109210659.md',
'Slava Akhmechet On Reading In Clusters 202109200659.md',
'Ideation In A 4X4 Matrix 202109200717.md',
'Drawing Grid Ideation 202109220830.md',
'Dictation 201208251425.md']

out = defaultdict(list)
for file in files:
    date = re.search(r'.*\s(\d+).md', file)
    if date:
        date = date.group(1)[:8]
        out[date].append(file)
print (out)

输出:

defaultdict(<class 'list'>, {'20210920': ['Tyler Cowen On Reading 202109200657.md', 'Slava Akhmechet On Reading In Clusters 202109200659.md', 'Ideation In A 4X4 Matrix 202109200717.md'], '20210921': ['On Poems 202109210659.md'], '20210922': ['Drawing Grid Ideation 202109220830.md'], '20120825': ['Dictation 201208251425.md']})

请注意,这段代码只是给出了逻辑,并没有得到目录中的文件列表,你只需要创建一个所有必需​​文件的列表并在上面的代码中使用该列表。

【讨论】:

    【解决方案3】:

    这是我理解的任务列表。

    1. 从文件名中提取字符串时间戳——字符串和列表处理

    2. 将时间戳(包括小时、分钟、秒)标准化为日期戳(仅限年-月-日)以在一天内对文档进行分组——日期处理

    3. 按每天的文档数量降序排序,然后在每天的文档数量范围内,按日期升序排序——稳定排序

    4. 在同一日期对文档进行分组,以某种方式处理它们——将函数传递给其他函数

    这涵盖了 Python 编程中相当多的基础,所以我将在进行过程中进行解释。

    我推荐使用 arrow 库来处理日期。 首先,安装箭头:

    pip install arrow

    import itertools
    from collections import Counter
    from pathlib import Path
    
    import arrow
    
    docs = [
        'Tyler Cowen On Reading 202109200657.md',
        'On Poems 202109210659.md',
        'Slava Akhmechet On Reading In Clusters 202109200659.md',
        'Ideation In A 4X4 Matrix 202109200717.md',
        'Drawing Grid Ideation 202109220830.md',
        'Dictation 201208251425.md',
    ]
    
    
    def datestamp(filename):
        basename = Path(filename).stem
        date_as_string = basename.split()[-1]
        timestamp = arrow.get(date_as_string, 'YYYYMMDDhhmm')
        return timestamp.format('YYYYMMDD')
    

    要从文件名中提取日期部分,您需要文档“基本名称”的最后一部分,在最后一个空格之后。

    Python 的.split() 方法将字符串拆分为空白处的列表(空格、制表符等):

    >>> basename = 'On Poems 202109210659'
    >>> basename.split()
    ['On', 'Poems', '202109210659']
    

    a_list[-1] 提取列表中的最后一项,因此:

    
    >>> basename.split()[-1]
    '202109210659'
    

    获取文件基本名称中最后一个空格之后的所有内容——时间戳。

    然后arrow 用于将时间戳转换为日期戳,以便忽略文档时间并将同一天的文档组合在一起。

    202109210659 -> 20210921
    

    使用箭头而不是正则表达式意味着您可以处理文件名中的不同日期格式。

    在这种情况下,将日期排序为字符串是可行的,因为所有日期都是 YMD 格式,年份(最大的部分)后跟月份和日期。如果我们对 DMY 日期进行排序,我们会得到意想不到的(和不需要的)结果。

    对于绘图数据:

    datestamps = [datestamp(doc) for doc in docs]
    datestamps.sort()
    docDates = Counter()
    for date in datestamps:
        docDates[date] += 1
    for date, doc_count in docDates.most_common():
        print(f'{date},{doc_count}')
    

    Counter() 是 Python 标准库中一个有用的类。 它的.most_common() 方法用于首先对文档最多的日期进行排序:

    >>> python docs.py
    20210920,3
    20120825,1
    20210921,1
    20210922,1
    

    请注意,1-doc 日期是按日期排序的二级。 datestamps.sort().most_common() 之前)是按日期排序的二级排序,因为 Python 库排序函数是“稳定的”。迭代 Counter() 遵循原始插入顺序,因此在文档计数相同的情况下,.most_common() 将保留 datestamps.sort() 的原始日期顺序。

    为了更好地理解稳定排序,see this answer。您可能需要多走几遍才能理解它。

    要对共享给定日期的文档进行分组,首先按 datestamp 函数对文档进行排序,然后按相同函数对它们进行分组。这使您可以处理与单个日期相关的所有文档(用于每日字数等)。为每个文件名计算日期戳“键”函数,然后用于在排序和分组时比较项目。

    docs.sort(key=datestamp)
    for date, docs_on_date in itertools.groupby(docs, key=datestamp):
        docs_today = list(docs_on_date)
        print(f'{date}: {docs_today}')
        # for doc in docs_today:
        #     # do_something_with(doc)
    

    结果:

    20120825: ['Dictation 201208251425.md']
    20210920: ['Tyler Cowen On Reading 202109200657.md', 'Slava Akhmechet On Reading In Clusters 202109200659.md', 'Ideation In A 4X4 Matrix 202109200717.md']
    20210921: ['On Poems 202109210659.md']
    20210922: ['Drawing Grid Ideation 202109220830.md']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      • 2015-01-20
      • 1970-01-01
      相关资源
      最近更新 更多