文件夹搜索算法

时间:2009-07-05 20:43:22

标签: database algorithm text-processing pseudocode

不确定这是否是这里常见的问题,或者我是否会得到任何答案,但我正在寻找一种伪代码方法来生成数据库链接记录包含图像文件的结构。

我有一组文件夹,结构如下:

+-make_1/
  | +--model_1/
  |    +-default_version/
  |    |   +--1999
  |    |   +--2000
  |    |   |   +--image_01.jpg
  |    |   |   +--image_02.jpg
  |    |   |   +--image_03.jpg
  |    |   |   ...
  |    |   +--2001
  |    |   +--2002
  |    |   +--2003
  |    |   ...
  |    |   +--2009
  |    +--version_1/
  |    |   +--1999
  |    |   ...
  |    |   +--2009
  |    +--version_2/
  |    |   +--1999
  |    |   +--2000
  |    |   +--2001
  |    |   |   +--image_04.jpg
  |    |   |   +--image_05.jpg
  |    |   |   +--image_06.jpg
  |    |   |   ...
  |    |   +--2002
  |    |   +--2003
  |    |   |   +--image_07.jpg
  |    |   |   +--image_08.jpg
  |    |   |   +--image_09.jpg
  |    |   ...
  |    |   +--2009
  ...  ... ...  

从本质上讲,它代表了车辆的可能图像,从1999年开始。

制作和模型(例如制作:阿尔法罗密欧,型号:145)有各种修剪或版本。每个装饰或版本都可以在许多车辆中找到,这些车辆看起来相同但是在燃料类型或发动机容量方面存在差异。

为了保存重复,上面的文件夹结构使用默认文件夹...并且图像从2000开始显示为默认版本。我需要为每个版本生成链接表 - 基于是否拥有自己的覆盖图像,或者是否使用默认版本...

因此,例如,version_1没有图像文件,因此我需要创建默认图像的链接,从2000年开始直到2009年。

另一方面,版本2在2000年开始使用默认图像,但随后在2001-2002和2003-2009之间首先使用两个新集。因此,所需的链接列表是......

version    start     end   file_name
=======    =====   =====   =========
version_1   2000    2009   image_01.jpg
version_1   2000    2009   image_02.jpg
version_1   2000    2009   image_03.jpg
...
version_2   2000    2001   image_01.jpg
version_2   2000    2001   image_02.jpg
version_2   2000    2001   image_03.jpg
version_2   2001    2003   image_04.jpg
version_2   2001    2003   image_05.jpg
version_2   2001    2003   image_06.jpg
version_2   2003    2009   image_07.jpg
version_2   2003    2009   image_08.jpg
version_2   2003    2009   image_09.jpg
...

(默认只是 - 占位符,并且不需要任何链接。)

目前我正在浏览文件夹,构建阵列,然后在最后修剪脂肪。我只是想知道是否有一个捷径,使用某种文本处理方法?大约有45,000个文件夹,其中大多数是空的: - )

1 个答案:

答案 0 :(得分:1)

这是一些Python伪代码,非常接近可执行文件(需要合适的导入和一个用于执行实际编写的编写器函数的def - 无论是中间文件,数据库,CSV,等等):

# first, collect all the data in a dict of dicts of lists
# first key is version, second key is year (only for non-empty years)

tree = dict()
for root, dirs, files in os.walk('make_1/model_1'):
    head, tail = os.path.split(root)
    if dirs:
       # here, tail is a version
       tree[tail] = dict
    elif files:
       # here, tail is a year
       tree[os.path.basename(head)][tail] = files

# now specialcase default_version
default_version = tree.pop('default_version')
# determine range of years; rule is quite asymmetrical:
#   for min, only years with files in them count
min_year = min(d for d in default_version if default_version[d])
#   for max, all years count, even if empty
max_year = max(default_version)

for version, years in tree.iteritems():
    current_files = default_version[min_year]
    years.append(max_year + 1)
    y = min_year
    while years:
        next_change = min(years)
        if y < next_change:
            for f in current_files:
                writerow(version, y, next_change-1, f)
        y = next_change
        current_files = years.pop(y)

规范和示例中的一个含糊之处是,default_version是否有可能在某些年份更改文件集 - 这里,我假设没有发生(只有特定版本改变了这种方式,默认版本总是如此)带有一组文件。)

如果不是这种情况,如果默认版本在1999年和2003年发生变化,并且版本1在2001年和2005年发生变化,那么会发生什么?版本1应该用于03和04的哪些文件,新的版本在默认版本,还是在01?

中指定的版本

在规范的最复杂版本中(默认版本和特定版本都可以更改,最近的更改优先,如果特定和默认值在同一年更改,则具体优先级更改)需要获取所有“下一个更改年份”序列,针对每个特定版本,通过仔细“优先合并”默认和特定版本的更改年份序列,而不是仅使用years(特定更改的顺序)正如我在这里所做的那样 - 当然,序列中的每个变更年份必须与适当的文件集相关联。

因此,如果可以表达确切的规范,直到极端情况,我可以通过修改这个伪代码来展示如何进行所需的合并 - 在确切的规范被澄清之前我宁愿不做这项工作,因为,如果规格确实比较简单,那么工作将是不必要的! - )

编辑:作为澄清的新评论,确切的规格确实是最复杂的,所以我们确实做了合适的合并。因此,上述简单回答结束时的循环变为:

for version, years_dict in tree.iteritems():
    # have years_dict override default_version when coincident
    merged = dict(default_version, **years_dict)
    current_files = merged.pop(min_year)
    merged[max_year + 1] = None
    y = min_year
    while merged:
        next_change = min(merged)
        for f in current_files:
            writerow(version, y, next_change-1, f)
        y = next_change
        current_files = merged.pop(y)

关键更改是merged = dict(...行:在Python中,这意味着合并一个新的dict(dict是一个通用映射,通常在其他语言中称为hashmap),这是总和,或者default_versionyears_dict的合并,但当两个密钥都存在时,years_dict的值优先 - 这符合当前一年的关键条件(即,两年都是文件更改的一年。

之后它一帆风顺:anydict.pop(somekey)返回与键对应的值(并将其从anydict中删除); min(anydict)返回字典中的最小键。请注意merged[max_year + 1] = None处的“哨兵”习语:这表示“最大一个之后”的年份始终被视为更改年份(虚拟占位符值为无),因此最后一组行总是正确写入(最长年份为max_year + 1 - 1,即根据需要正好max_year

这种算法不是最有效的,只是最简单的!我们一遍又一遍地做min(merged),使其成为O(N平方) - 我认为我们可以负担得起,因为每个merged最多应该有几十个变化年,但纯粹主义者会畏缩。我们当然可以提供一个O(N logN)解决方案 - 只需对这些年份进行一次排序,然后按顺序执行next_change的连续值。只是为了完整......:

default_version[max_year + 1] = None

for version, years_dict in tree.iteritems():
    merged = dict(default_version, **years_dict)
    for next_change in sorted(merged):
        if next_change > min_year:
            for f in merged[y]:
                writerow(version, y, next_change-1, f)
        y = next_change

此处sorted按排序顺序提供了一个包含merged键的列表,并且我已切换到for语句以从头到尾遍历该列表(以及if声明在第一次输出时没有输出)。现在,sentinel被置于default_version中(所以它在循环之外,进行另一次轻微优化)。很有趣的是,这个优化版本(主要是因为它在略高的抽象级别上工作)结果比以前更小更简单; - )。