【问题标题】:binning files into approximately equal sized directories将文件分箱到大小大致相等的目录中
【发布时间】:2013-04-15 14:01:46
【问题描述】:

给定一个格式为文件名的排序列表

{artist}-{title}.mp3

我想将文件分配到 255 个 bin(子目录)中,以便每个 bin 包含大致相等数量的文件,并限制艺术家是“原子的”,即任何艺术家都不应将曲目分布在多个目录中。结果也应该保持排序(即忽略分箱,我们仍然有相同的列表排序)。

我已经尝试过:我通过这种方法将列表分成 255 个部分:

def partition(lst, n):
    q, r = divmod(len(lst), n)
    indices = [q * i + min(i, r) for i in range(n + 1)]
    result = [lst[indices[i]:indices[i + 1]] for i in range(n)]
    assert sum(len(x) for x in result) == len(lst)
    assert len(set(len(x) for x in result)) <= 2
    return result

然后,如果艺术家已经有另一首曲目,我会通过将他们移到前一个 bin 中来执行并强制执行艺术家是原子的限制。这种方法是次优的并且被破坏了,因为我留下了很多空箱(由于在某些情况下,同一艺术家的许多曲目)

【问题讨论】:

  • 我没有时间实现这个,所以这里有一些伪代码:从列表中获取艺术家姓名,将属于该艺术家的所有文件移动到单独的列表中(称之为@ 987654323@) 并将它们从初始列表中删除。获取其中文件最少的目录(为此编写一个函数),将列表a中的文件添加到您之前获得的目录中。重复此操作,直到您的初始列表中没有更多文件。
  • 对不起,我忘记指定应该保留排序,这意味着您的建议不起作用。我会把它编辑成问题...

标签: python language-agnostic


【解决方案1】:

在研究了一个小时后,我想出了一个更好的解决方案。它的工作原理是创建一个艺术家的dict 到轨道,然后通过贪婪地配对较小的相邻条目来将其缩减到 255 个键。

我确信它仍然不是最佳的,但它是可行的,我会在这里重现它,以防有人有类似的问题需要解决:

d = collections.OrderedDict()
# build an OrderedDict of artist to track(s)
for fn in files:
    artist, title = fn.split('-')
    if (artist,) not in d:
        d[artist,] = []
    d[artist,].append(fn)

def window(seq, n=2):
    it = iter(seq)
    result = tuple(itertools.islice(it, n))
    if len(result) == n:
        yield result    
    for elem in it:
        result = result[1:] + (elem,)
        yield result

while len(d) > 255:
    # find the pair of adjacent keys with minimal number of files contained
    k1, k2 = min(window(d), key=lambda x: len(d[x[0]] + d[x[1]]))
    # join them into the first key and nuke the latter
    d[k1] += d.pop(k2)

【讨论】:

  • 这大概是我的想法。如果没有任何关于样本按字母顺序分布的预知,我认为它是赢家。当然,根据样本大小,对数据进行 2 次遍历可能会产生更好的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 2021-07-13
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多