将数组拆分为大致相等的块

时间:2015-02-19 09:09:42

标签: python python-2.7

当每个块的总和大致相等时,如何将数组拆分成两个块?

>>> foo([10, 1, 1, 1])
[[10], [1, 1, 1]]
>>> foo([2, 5, 9, 5, 1, 1])
[[2, 5], [9, 5, 1, 1]]
>>> foo([9, 5, 5, 8, 2, 2, 18, 8, 3, 9, 4])
[[9, 5, 5, 8, 2, 2], [18, 8, 3, 9, 4]]
>>> foo([17, 15, 2, 18, 7, 20, 3, 20, 12, 7])
[[17, 15, 2, 18, 7], [20, 3, 20, 12, 7]]
>>> foo([19, 8, 9, 1, 14, 1, 16, 4, 15, 5])
[[19, 8, 9, 1], [14, 1, 16, 4, 15, 5]]

5 个答案:

答案 0 :(得分:2)

类似的东西:

def foo(lst):
    total_sum = sum(lst)
    i = 1
    while sum(lst[:i]) < total_sum / 2:  # iterate over the list slices until we hit the "middle" 
        if sum(lst[:i+1]) >= total_sum / 2:  # also make sure that we won't go further
            break

        i += 1

    return [lst[:i], lst[i:]]

测试:

[[10], [1, 1, 1]]                         # 10 + 3
[[2, 5], [9, 5, 1, 1]]                    # 7 + 16
[[9, 5, 5, 8, 2, 2], [18, 8, 3, 9, 4]]    # 31 + 42
[[17, 15, 2, 18, 7], [20, 3, 20, 12, 7]]  # 59 + 62
[[19, 8, 9, 1], [14, 1, 16, 4, 15, 5]]    # 37 + 55

答案 1 :(得分:2)

您可以在列表上创建包含循环的切片,然后使用正确的密钥选择具有min功能的正确对:

>>> def find_min(l):
...     return min(((l[:i],l[i:]) for i in range(len(l))),key=lambda x:abs((sum(x[0])-sum(x[1]))))

演示:

>>> l=[10, 1, 1, 1]
>>> find_min(l)
([10], [1, 1, 1])
>>> l=[9, 5, 5, 8, 2, 2, 18, 8, 3, 9, 4]
>>> find_min(l)
([9, 5, 5, 8, 2, 2], [18, 8, 3, 9, 4])
>>> l=[19, 8, 9, 1, 14, 1, 16, 4, 15, 5]
>>> find_min(l)
([19, 8, 9, 1, 14], [1, 16, 4, 15, 5])

答案 2 :(得分:1)

假设当列表在列表的累积总和尽可能接近整个列表总和的一半时被分区时,获得最佳分割:

import numpy as np

x = [19, 8, 9, 1, 14, 1, 16, 4, 15, 5]
csum = np.cumsum(x)
ix = np.argmin(abs(csum-csum[-1]/2)) + 1
result = [x[:ix], x[ix:]]

结果:

[[19, 8, 9, 1, 14], [1, 16, 4, 15, 5]]

答案 3 :(得分:0)

这是我的解决方案:

def sum(*args):
    total = 0
    if len(args) > 0:
        for i in args:
            for element in i:
                total += element
    return total

def foo(Input):
    size = len(Input)
    checkLeftCross = 0
    previousLeft = 0
    previousRight = 0
    currentLeft = 0
    currentRight = 0
    targetIndex = 0
    for i in range(size):
        currentLeft = sum(Input[0:i])
        currentRight = sum(Input[i:size])
        if currentLeft >= currentRight:
            targetIndex = i
            break
        else:
            previousLeft = currentLeft
            previousRight = currentRight

    diffPrev = previousRight - previousLeft
    diffCurr = currentLeft - currentRight

    if diffPrev > diffCurr:
        return Input[0:targetIndex], Input[targetIndex:size]
    else:
        return Input[0:targetIndex-1], Input[targetIndex-1:size]

def main():
    print foo([2, 5, 9, 5, 1, 1])
    print foo([10,1,1,1])
    print foo([9, 5, 5, 8, 2, 2, 18, 8, 3, 9, 4])
    print foo([17, 15, 2, 18, 7, 20, 3, 20, 12, 7])
    print foo([19, 8, 9, 1, 14, 1, 16, 4, 15, 5])

if __name__ == "__main__":
    main()

说明:

  1. 我使用函数sum来返回列表中所有元素的总和。
  2. funciton foo在检查后是否分割后返回2个列表 在此基础上,目前的分割比先前的分割更好或更差 两个连续总和之间的差异。
  3. 输出:

    ([2, 5], [9, 5, 1, 1])
    ([10], [1, 1, 1])
    ([9, 5, 5, 8, 2, 2], [18, 8, 3, 9, 4])
    ([17, 15, 2, 18, 7], [20, 3, 20, 12, 7])
    ([19, 8, 9, 1, 14], [1, 16, 4, 15, 5])
    

答案 4 :(得分:0)

from itertools import combinations
from collections import Counter


def most_equal_pairs(seq, n=None):
    seq_mapping = dict(enumerate(seq))

    if len(seq_mapping) < 2:
        raise ValueError()
    if len(seq_mapping) == 2:
        first, second = seq_mapping.values()
        yield [first], [second], abs(first - second)
        return

    ids = set(seq_mapping)

    def get_chunk_by_ids(ids):
        return [seq_mapping[i] for i in ids]

    def get_chunk_sum_by_ids(ids):
        return sum(get_chunk_by_ids(ids))

    pairs = Counter()

    for comb_len in range(1, len(ids) - 1):
        for first_comb in combinations(ids, comb_len):
            second_comb = tuple(ids - set(first_comb))
            first_sum = get_chunk_sum_by_ids(first_comb)
            second_sum = get_chunk_sum_by_ids(second_comb)
            diff = abs(first_sum - second_sum)
            pairs[(first_comb, second_comb)] = -diff

    for (first_comb_ids, second_comb_ids), diff in pairs.most_common(n):
        first_comb = get_chunk_by_ids(first_comb_ids)
        second_comb = get_chunk_by_ids(second_comb_ids)
        yield first_comb, second_comb, abs(diff)


def test(seq):
    pairs = list(most_equal_pairs(seq))
    diff_seq = []

    for first, second, diff in pairs:
        assert abs(sum(first) - sum(second)) == abs(diff)
        diff_seq.append(diff)

    assert tuple(sorted(diff_seq)) == tuple(diff_seq)
    best_pair = pairs[0]
    first, second, diff = best_pair
    return first, second, sum(first), sum(second), diff

结果

>>> test([10, 1, 1, 1])
([10], [1, 1, 1], 10, 3, 7)

>>> test([2, 5, 9, 5, 1, 1])
([2, 9, 1], [5, 5, 1], 12, 11, 1)

>>> test([9, 5, 5, 8, 2, 2, 18, 8, 3, 9, 4])
([5, 8, 2, 2, 8, 3, 9], [9, 5, 4, 18], 37, 36, 1)

>>> test([17, 15, 2, 18, 7, 20, 3, 20, 12, 7])
([18, 3, 20, 12, 7], [17, 15, 2, 7, 20], 60, 61, 1)

>>> test([19, 8, 9, 1, 14, 1, 16, 4, 15, 5])
([19, 9, 14, 4], [8, 1, 1, 16, 15, 5], 46, 46, 0)