[英]Is there a more efficient way to solve this?
Consider the following N × N matrices A and B that contain only positive integers: 考虑以下仅包含正整数的N×N个矩阵A和B :
[i,j]
in A . B是通过在A中位置[i,j]
求和与每个元素相邻的奇数而从A中创建的 。 [i,j]
in B . 然后将每个计算出的总和存储在B中的对应位置[i,j]
中。 For example: 例如:
[3, 2]
there are 4
odd numbers [3, 1, 5, 3]
that neighbour A[3,2]
. 在位置[3, 2]
有4
奇数[3, 1, 5, 3]
该邻居A[3,2]
。 12
, which is stored in B[3,2]
这些相邻的奇数之和为12
,存储在B[3,2]
This code works by brute force, taking each of the 9 regions separately, (Namely: Top, bottom, left, right, 4 corners and inner). 该代码通过蛮力工作,将9个区域分别分开(即:上,下,左,右,4个角和内部)。
Is there a better way to go about this? 有没有更好的方法来解决这个问题?
from numpy import array,zeros,shape
def sum_neighbours(A):
A = array(A,int)
r,c = shape(A)
B = zeros(shape(A),int)
for i in range(r):
for j in range(c):
N_list_i = [0,-1,-1,-1,0,1,1,1,0] #[l,tl,t,tr,r,br,b,bl]
N_list_j = [-1,-1,0,1,1,1,0,-1,-1]
# innerSquares
if 1 <= i <= (r-2) and 1 <= j <= (r-2):
for k in range(len(N_list_j)-1):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#TopLeft
elif i==0 and j==0:
N_list_i = N_list_i[4:(4+3)]
N_list_j = N_list_j[4:(4+3)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#BottomLeft
elif j==0 and i==(r-1):
N_list_i = N_list_i[2:(2+3)]
N_list_j = N_list_j[2:(2+3)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#TopRight
elif i==0 and j == (r-1):
N_list_i = N_list_i[6:(6+3)]
N_list_j = N_list_j[6:(6+3)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#BottomRight
elif i == (r-1) and j == (r-1):
N_list_i = N_list_i[0:(0+3)]
N_list_j = N_list_j[0:(0+3)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#TopBorder
elif i==0 and j < (r-1):
N_list_i = N_list_i[4:(4+5)]
N_list_j = N_list_j[4:(4+5)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#LeftBorder
elif j==0 and i < (r-1):
N_list_i = N_list_i[2:(2+5)]
N_list_j = N_list_j[2:(2+5)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#BottomBorder
elif i==(r-1) and j < (r-1):
N_list_i = N_list_i[0:(0+5)]
N_list_j = N_list_j[0:(0+5)]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
#RightBorder
elif j==(r-1) and i < (r-1):
N_list_i = [1,1,0,-1,-1]
N_list_j = [0,-1,-1,-1,0]
for k in range(len(N_list_j)):
if A[i+N_list_i[k]][j+N_list_j[k]] %2 != 0:
B[i][j] += A[i+N_list_i[k]][j+N_list_j[k]]
return B
A = array([[3,2,8,1,1],
[1,2,4,1,1],
[7,3,4,1,8],
[1,8,0,6,4],
[5,6,5,3,8]])
In terms of refactoring, you almost certainly want to avoid "brute force" in the sense of having to explicitly type out all your cases :) @alexmcf addresses this above. 在重构方面,您几乎肯定希望避免“蛮力”,因为必须明确地键入所有情况:) @alexmcf解决了上述问题。
In conceptual terms, your approach follows the problem statement directly: check all neighbors for each number in the matrix and sum all odd numbers. 从概念上讲,您的方法直接遵循问题陈述:检查矩阵中每个数字的所有邻居并将所有奇数求和。 This means that you are always doing the checking and summing, even if there are no odd numbers in the matrix. 这意味着即使矩阵中没有奇数 , 也始终要进行检查和求和。
As an alternative: we can first run through the matrix and identify odd numbers. 作为替代方案:我们可以首先遍历矩阵并确定奇数。 Then, starting from a null matrix, we simply add the odd numbers to all valid neighbors. 然后,从一个零矩阵开始,我们只需将奇数添加到所有有效邻居中即可。 This saves work in proportion to the sparcity of odd numbers in the matrix. 与矩阵中奇数稀疏性成比例地节省了工作。
import numpy as np
def find_offsets(row, col, size):
"""Return all valid pairs of offsets as [(row_offset, col_offset)...]."""
offsets = ((-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1))
return [(r_off, c_off) for r_off, c_off in offsets
if row + r_off >= 0 and row + r_off < size
if col + c_off >= 0 and col + c_off < size]
def find_odds(matrix, size):
"""Return all odd values in matrix as [(row_ind, col_ind, value)...]."""
return [(row, col, matrix[row][col])
for row in xrange(size)
for col in xrange(size)
if matrix[row][col] % 2 != 0]
def gen_matrix(source, size):
"""Filter source 2x2 matrix for odds and add each to valid neighbors."""
out = np.zeros((size, size), dtype=int)
# filter for location and value of all odd numbers
odds = find_odds(source, size)
for row, col, value in odds:
# add odd number to all valid neighbors (by finding valid offsets)
offsets = find_offsets(row, col, size)
for r_off, c_off in offsets:
out[row + r_off][col + c_off] += value
return out
def sum_neighbors():
"""Sum neighbors as described in problem."""
N = 5
A = [[3,2,8,1,1],
[1,2,4,1,1],
[7,3,4,1,8],
[1,8,0,6,4],
[5,6,5,3,8]]
return gen_matrix(A, N)
The above runs about twice as fast as your code (for an apples-to-apples comparison, I tweaked the above when executing in iPython so that the same matrix A is provided as a parameter in both cases): 上面的代码运行速度是您代码的两倍(为了进行苹果之间的比较,我在iPython中执行时对上面的代码进行了调整,以便在两种情况下都提供相同的矩阵A作为参数):
In [19]: %timeit original.sum_neighbours(A)
1000 loops, best of 3: 195 µs per loop
In [20]: %timeit new.sum_neighbors(A)
10000 loops, best of 3: 84 µs per loop
import numpy as np
def sum_neighbours_NEW(A):
A = np.array(A,int)
r,c = np.shape(A)
B = np.zeros(A.shape, int)
def b(x,y, size=A.shape):
xlim,ylim = size # get limits of axes
# generate a list of all i,j bordering x,y
# this will cause the most slowdown... for faster code, you minimise
# the number of tims idx gets called by making it a parameter of b()
# adding x and y and doing a np.where() to ensure it doesn't
# index out of the array range
idx = [[x+i,y+j] for i in range(-1,2) for j in range(-1,2) \
if (i,j) != (0,0) and (x+i>=0 and y+j>=0) and (x+i<xlim and y+j<ylim)]
idx = np.asarray(idx) # convert to numpy array
return idx[:,0], idx[:,1] # split into x,y for indexing
# iterate across all elements of A
for i in xrange(r):
for j in xrange(c):
els = A[b(i,j)]
sum_A = els[np.where(els % 2)].sum() # only sum odd elements
B[i,j] = sum_A
return B
A = array([[3,2,8,1,1],
[1,2,4,1,1],
[7,3,4,1,8],
[1,8,0,6,4],
[5,6,5,3,8]])
# check new function vs. old function
(sum_neighbours(A) == sum_neighbours_NEW(A)).all()
True
Try this loop for scanning across the 'surrounding elements', it returns a tuple of x,y
elements split into individual x
and y
arrays as specified by numpy indexing 尝试执行此循环以扫描“周围的元素”,它返回x,y
元素的元组x,y
元素分为numpy索引指定的单个x
和y
数组
def b(x,y, size=A.shape):
xlim,ylim = size # get limits of axes
# generate a list of all i,j bordering x,y
idx = [[x+i,y+j] for i in range(-1,2) for j in range(-1,2) \
if (i,j) != (0,0) and (x+i>=0 and y+j>=0) and (x+i<xlim and y+j<ylim)]
idx = np.asarray(idx) # convert to numpy array
return idx[:,0], idx[:,1] # split into x,y for indexing
idx = b(3,2)
# check correct by matching indexes e.g.
# (idx[0][0],idx[1][0]) => (2,1) , (idx[0][1],idx[1][1]) => (2,2) etc.
print idx
(array([2, 2, 2, 3, 3, 4, 4, 4]), array([1, 2, 3, 1, 3, 1, 2, 3]))
Then you can access elements in A by: 然后,您可以通过以下方式访问A中的元素:
els = A[idx]
print els
array([3, 4, 1, 8, 6, 6, 5, 3])
You can then sum all elements that are odd by: 然后可以通过以下方式求和所有奇数元素:
print els[np.where(els % 2)].sum()
12
use this to obtain the sum across every element in A . 用它来获得A中每个元素的和。
The top portion of this should help out in getting just the odd elements. 顶部应该有助于获得奇怪的元素。
import numpy as np
# generate an array of random integers
A = np.random.random_integers(1,10, [20,10])
# get only the odd values back from the array
A_odds = A*(A%2!=0)
# pad the array with zeros to make summing easier
A_odds_padded = np.pad(array=A_odds, pad_width=1, mode='constant')
# iterate elements and sum
B = np.zeros(np.shape(A))
for i in range(shape(B)[0]):
for j in range(shape(B)[1]):
#etc
I have this: 我有这个:
def find_odd_sum(arr):
# Pad the original array
arr_pad = np.pad(arr, 1, 'constant', constant_values=0)
shape = np.shape(arr)
arr_b = np.zeros((shape[0] + 2, shape[1] + 2))
for ii in range(0, shape[0]): #rows
for jj in range(0, shape[1]): #cols
point = np.array([ii+1, jj+1])
# Points to check
kernel = [np.array([-1, 0]),
np.array([0, 1]),
np.array([1, 0]),
np.array([0, -1]),
np.array([-1, -1]),
np.array([1, 1]),
np.array([-1, 1]),
np.array([1, -1])]
points = [k+point for k in kernel]
s = [arr_pad[points[i][0], points[i][1]] for i in range(len(points))]
s1 =sum([i for i in s if i % 2 != 0])
arr_b[point[0], point[1]] = s1
return arr_b[1:-1, 1:-1]
>>>
[[ 1. 4. 2. 3. 3.]
[ 13. 14. 6. 4. 4.]
[ 5. 9. 5. 2. 3.]
[ 15. 21. 12. 9. 4.]
[ 1. 11. 3. 5. 3.]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.