Как найти сумму слоя чисел в ndarray
У меня есть массив 10*10. Мне нужно найти сумму всех слоев. Следующий рисунок прояснит мой вопрос:
Как я могу сделать это легко?
5 ответов
вот решение без повторного суммирования одних и тех же элементов и без промежуточного массива (просто удовольствие от индексирования грубой силы), которое работает для square n
by n
массивы для нечетных или даже n
:
import numpy as np
def sum_shells(a):
n = len(a)
no2 = n // 2
shell_sums = []
for i in range(no2):
shell_sums.append(np.sum(a[i,i:n-i]) + np.sum(a[n-i-1,i:n-i]) +
np.sum(a[i+1:n-i-1,i]) + np.sum(a[i+1:n-i-1,n-i-1]))
if n % 2:
shell_sums.append(a[no2, no2])
return shell_sums
a = np.array([
[8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
[8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
[8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
[3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
[6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
[8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
[7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
[6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
[9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
[2, 8, 6, 3, 6, 5, 0, 3, 1, 8] ])
b = np.array([[9, 5, 8, 6, 5],
[1, 1, 0, 5, 1],
[5, 9, 7, 0, 0],
[7, 4, 7, 5, 1],
[9, 5, 0, 2, 3] ])
print(sum_shells(a))
print(sum_shells(b))
выдает:
[170, 122, 85, 62, 17]
[67, 31, 7]
просто добавить еще один ответ... Хотя общая идея вычитания внутренних квадратов из внешних, вероятно, является лучшим подходом, если вы хотите производительность, ни одна из представленных реализаций не будет слишком хорошей, так как они продолжают добавлять одни и те же числа снова и снова. Чтобы ускорить этот расчет, вы можете использовать то, что в обработке изображений называется интегральным изображением:
>>> int_arr = np.cumsum(np.cumsum(arr, axis=0), axis=1)
>>> int_arr
array([[ 8, 8, 15, 19, 22, 22, 22, 29, 35, 44],
[ 16, 17, 24, 34, 40, 44, 46, 54, 64, 79],
[ 24, 30, 46, 62, 76, 80, 82, 91, 104, 119],
[ 27, 35, 59, 84, 103, 115, 123, 137, 156, 178],
[ 33, 48, 77, 103, 123, 135, 148, 163, 191, 213],
[ 41, 65, 98, 129, 158, 177, 190, 205, 233, 259],
[ 48, 81, 120, 158, 191, 217, 235, 251, 286, 316],
[ 54, 95, 136, 180, 214, 249, 275, 296, 333, 364],
[ 63, 105, 147, 194, 235, 276, 310, 331, 376, 414],
[ 65, 115, 163, 213, 260, 306, 340, 364, 410, 456]])
из этого вспомогательного массива вы можете вычислить площадь любого прямоугольного поддерева, добавив две записи и вычитание двух других, например:
>>> np.sum(arr[1:-1, 1:-1])
286
>>> int_arr[-2,-2] + int_arr[0, 0] - int_arr[-2, 0] - int_arr[0, -2]
286
С этим вы можете легко вычислить свои суммы, например:
sums = [int_arr[-1, -1]]
top = 0
bot = len(arr) - 2
while top < bot:
new_sum = (int_arr[bot, bot] + int_arr[top, top] -
int_arr[top, bot] - int_arr[bot, top])
sums[-1] -= new_sum
sums.append(new_sum)
top += 1
bot -= 1
>>> sums
[170, 122, 85, 62, 17]
если вы знаете, как сделать сумму (2n)*(2n)
квадрат посередине, тогда это очень просто: возьмите сумму (2n)*(2n)
квадрат, затем вычесть сумму (2n-2)*(2n-2)
квадрат внутри него; разница-это сумма элементов на границе (то есть находятся во внешнем квадрате, но не во внутреннем):
import numpy
# let x be a 10 * 10 array
x = numpy.array([
[8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
[8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
[8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
[3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
[6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
[8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
[7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
[6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
[9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
[2, 8, 6, 3, 6, 5, 0, 3, 1, 8],
])
for i in xrange(1, 6): # loop with i = 1,...,5
# find the sum of the (2i)*(2i) square in the middle
a = numpy.sum(x[5-i:5+i, 5-i:5+i])
# find the sum of the (2i-2)*(2i-2) square in the middle
b = numpy.sum(x[6-i:4+i, 6-i:4+i])
# the difference gives the sum of the elements on the border
s = a - b
print s
17
62
85
122
170
код ниже вычисляет каждый слой, а затем вычитает из него меньший слой. Это довольно общий, и поэтому любой массив размера N*N должен быть передан ему, пока N
еще (я думаю).
import numpy as np
arr = np.array([[8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
[8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
[8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
[3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
[6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
[8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
[7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
[6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
[9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
[2, 8, 6, 3, 6, 5, 0, 3, 1, 8]])
N = len(arr)
def sum_layer(arr, M, N=N):
"""Function to return the sum of a layer."""
return arr[M:N-M, M:N-M].sum()
# Each of the layers.
layers = [sum_layer(arr, i) for i in range(N - N//2)]
# Subtract the smaller areas from the larger, to get the margins.
result = [layers[i] - layers[i+1] for i in range(N//2 - 1)]
# Need to add the final, smallest layer on.
result.append(layers[-1])
print(result)
# [170, 122, 85, 62, 17]
У меня есть идея. 1-й найдите сумму всего массива 10 * 10, затем найдите сумму внутреннего массива 9*9. Тогда вычитание является результатом суммы внешнего слоя.
for i in range(len(A)/2):
B = A[1:-1, 1:-1]
print sum(A)-sum(B)
A = B
цикл найдет всю сумму.
может быть, есть лучший способ сделать это..