给出表单
的文件名的排序列表{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
然后,如果他们已经在那里有另一条轨道,我会通过将艺术家移动到前一个箱子中来强制执行艺术家原子的限制。这种方法是次优和破坏的,因为我留下了很多空箱(由于在某些情况下,由于同一艺术家有许多轨道)
答案 0 :(得分: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)