1

我有一个文件,假设我需要将它拆分为最多 N 个较小的文件,并且最小的块应该至少有 X 个字节,并且所有文件应该(几乎)具有相同的大小:

因此,使用例如 N=4 和 X=3 的字符串 'abcdefghij' 将返回 ['abcd', 'efg', 'hij'] 因为:

3 chunks < 4 chunks
4 chars > 3 chars

我写了一个拆分函数,但它有时会创建一个额外的字符串,所以我可能应该传递x值而不是在那里计算。

def split(string, n):
    x = len(string)//n
    return [string[i:i+x] for i in range(0, len(string), x)]

真正的问题是如何计算以最小字节数切割文件的块数。

def calculate(length, max_n, min_x):
    n, x = ...
    return n, x

是否有一个简单的已知算法来执行这种操作?

实际上:文件不需要在 1 个字节上有所不同,因为我想最大化块的数量。

4

3 回答 3

0

你是什​​么意思,“用最少的字节数剪切文件”?要么您没有完全解释问题,要么没有唯一的解决方案。

正如您的解决方案所示,这是一个划分问题:如果L是总长度,您可以将其划分n任何 n < L. 余数(必然小于n)为您提供比其他字符多一个字符的块数。例如,10 % 3 = 1因此在您的示例中,三个块之一更长。但是你可以划分10 % 7(余数 3),得到七个块,其中三个更长(长度为 2 而不是 1)。或者只有 10 个长度为 1 的块,如果你真的一心想“最大化块的数量”,就像你写的那样。

更一般地说:对于m您指定的任何长度,选择N = L // m并且您的块将具有长度mm+1(或者只有m,如果L // m没有余数)。正如我所说,这只是一个划分问题。

于 2012-09-10T22:37:12.003 回答
0

不确定简单或已知,但这似乎可以解决问题。它返回 N 个字符串,其中额外的字符分配给集合中较早的字符串。

import itertools as it
s = 'abcdefhijklm'
def hunks(s, n):
    size, extra = divmod(len(s), n)
    i = 0
    extras = it.chain(it.repeat(1, extra), it.repeat(0))
    while i < len(s):
        e = next(extras)
        yield s[i:i + size + e]
        i += size + e
list(hunks(s, 4))
于 2012-09-10T22:38:22.423 回答
0
def calculate(L, N, X):
    n = min(L//X, N)
    return n, L//n

编辑:

def spread(seq, N=None, X=1):
    """Yield successive subsequences of seq having at least X elements.

    If N is specified, the number of subsequences yielded will not exceed N.

    The first L % X subsequences yielded (where L = len(seq)) will be longer
    by 1 than the remaining ones.

    >>> list(spread('abcdefghij', 4, 3))
    ['abcd', 'efg', 'hij']
    >>> list(spread('abcdefghijklmnopqrstuvwxyz', 4, 7))
    ['abcdefghi', 'jklmnopqr', 'stuvwxyz']

    seq    any object supporting len(...) and slice-indexing
    N      a positive integer (default: L)
    X      a positive integer not greater than L (default: 1)
    """

    # All error-checking code omitted

    L = len(seq)       # length of seq
    assert 0 < X <= L

    if N is None: N = L
    assert 0 < N

    # A total of n subsequences will be yielded, the first r of which will 
    # have length x + 1, and the remaining ones will have length x.

    # if we insist on using calculate()...
    # n, x = calculate(L, N, X)
    # r = L % n

    # ...but this entails separate computations of L//n and L%n; may as well
    # do both with a single divmod(L, n)
    n = min(L//X, N)
    x, r = divmod(L, n)

    start = 0
    stride = x + 1    # stride will revert to x when i == r
    for i in range(n):
        if i == r: stride = x
        finish = start + stride
        yield seq[start:finish]
        start = finish
    assert start == L
于 2012-09-11T13:33:22.070 回答