I want to get all neighbour values of a np.array.
The array looks like:
x = np.array([ [1, 2, 3, 4 ],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16] ])
What I have is:
i = 2
j = 2
n = x[i,j-1], x[i,j], x[i,j+1], x[i-1,j], x[i+1,j], x[i-1,j-1], x[i+1,j+1], x[i+1,j-1], x[i-1,j+1]
This returns (what I want)
(10, 11, 12, 7, 15, 6, 16, 14, 8)
But also got bugs for example when i want the neightbour values of
i = 3
j = 3
That gives:
Exception has occurred: IndexError
index 4 is out of bounds for axis 1 with size 4
An other soultion is:
def find_neighbors(m, i, j, dist=1):
return [row[max(0, j-dist):j+dist+1] for row in m[max(0,-1):i+dist+1]]
and
n = find_neighbors(x, i, j)
Which gives me an array of the neightbours but also gives me not all neightbours when I set
i = 0
j = 0
because it only gives me:
[array([1, 2]), array([5, 6])]
Does anybody have a solution for this?
Thank you!
You can take advantage of python indexing wrapping around for negative indices.
def wrap_nb(x,i,j):
return x[np.ix_(*((z-1, z, z+1-S) for z,S in zip((i,j), x.shape)))].ravel()
This requires i and j to be nonnegative and less than the shape of x.
If that is not guaranteed:
def wrap_nb(x,i,j):
return x[np.ix_(*(np.r_[z-1:z+2]%S for z,S in zip((i,j), x.shape)))].ravel()
Examples:
>>> wrap_nb(x,1,-2)
array([ 2, 3, 4, 6, 7, 8, 10, 11, 12])
>>> wrap_nb(x,0,-1)
array([15, 16, 13, 3, 4, 1, 7, 8, 5])
>>> wrap_nb(x,0,0)
array([16, 13, 14, 4, 1, 2, 8, 5, 6])
# function to find the start row and column
def find_start(x):
start = x-1 if x-1 >= 0 else 0
return start
# function to find the end row and column
def find_end(x, shape):
end = x+1 if x+1 <= shape else shape
return end
def find_neighbors(a, i, j):
neighbors = []
row_start, row_end = find_start(i), find_end(i, a.shape[0])
col_start, col_end = find_start(j), find_end(j, a.shape[1])
for y in range(a.shape[0]):
for z in range(a.shape[1]):
if y >= row_start and y <= row_end:
if z >= col_start and z <= col_end:
neighbors.append(a[y][z])
return neighbors
i, j = 0, 0
neighbors = find_neighbors(a, i, j)
print(neighbors)
Output: [1, 2, 5, 6]
i, j = 3, 3
neighbors = find_neighbors(a, i, j)
neighbors
Output: [11, 12, 15, 16]
i, j = 2, 2
neighbors = find_neighbors(a, i, j)
neighbors
Output: [6, 7, 8, 10, 11, 12, 14, 15, 16]
This would cover all the edge cases.
I got the following solution form an mate:
New array:
homes = np.array([ [1, 2, 3, 4 ],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16] ])
Code for returning the neighbour values:
neighbour = []
neighbour += [homes[i][j]] # value itself
neighbour += [homes[i][(j + 1) % n]] # value right
neighbour += [homes[i][(j - 1) % n]] # value left
neighbour += [homes[(i + 1) % n][j]] # value down
neighbour += [homes[(i + 1) % n][(j + 1) % n]] # value right down
neighbour += [homes[(i + 1) % n][(j - 1) % n]] # value left down
neighbour += [homes[(i - 1) % n][j]] # vlaue up
neighbour += [homes[(i - 1) % n][(j + 1) % n]] # vlaue right up
neighbour += [homes[(i - 1) % n][(j - 1) % n]] # value left up
Which returns me:
i = 0
j = 0
[16, 13, 15, 4, 1, 3, 12, 9, 11]
Thats what I need but I'am still interessed in solution like the one from Abdur
Related
For example I have an array of:
array = {
1, 2, 3,
4, 5, 6,
7, 8, 9
}
Is it possible if I can make it go counter-clockwise starting from 9 to 5, then the output should look like:
9 6 3 2 1 4 7 8 5
I want it in plain python with no imported modules, Thank you in advance!
This is what i tried but it just reverse
arr = {
1, 2, 3,
4, 5, 6,
7, 8, 9
}
{print(i, end=' ') for i in list(arr)[::-1]}
Ok here's a recursive function that will spiral an array of any dimensions (square or rectangular); note that is empties the original array, so if you want to keep it, you'll have to first make a deepcopy of it:
array = [
[1,2,3,4,5,6],
[7,8,9,10,11,12],
[13,14,15,16,17,18],
[19,20,21,22,23,24]
]
def spiral(array, sp=[] , direction = 0):
# direction = 0 for up, 1 for left, 2 for down, 3 for right
if array == []:
return sp
if direction == 0:
for i in range(len(array)-1,-1,-1):
sp.append(array[i][-1])
del array[i][-1]
return spiral(array, sp, 1)
if direction == 1:
sp += array[0][::-1]
del array[0]
return spiral(array, sp, 2)
if direction == 2:
for i in range(len(array)):
sp.append(array[i][0])
del array[i][0]
return spiral(array, sp, 3)
if direction == 3:
sp += array[-1]
del array[-1]
return spiral(array, sp, 0)
print(spiral(array))
# [24, 18, 12, 6, 5, 4, 3, 2, 1, 7, 13, 19, 20, 21, 22, 23, 17, 11, 10, 9, 8, 14, 15, 16]
I have a problem. In my code I need to do the following:
I have an array like this: [1, 5, 7, 9, 10, 11, 14, 15]
Now I need to determine in the most efficient way what the closest values are for a given x. For example:
array = [1, 5, 7, 9, 10, 11, 14, 15]
above, below = myFunction(array, 8)
Should return 7 and 9
If there is no number higher or lower than the given number, the value that couldn't be determined should be None. If the same number is given as in the array, for example: 7. The values 5 and 9 should be returned.
I know there is a min() and max() function, but I couldn't find anything in my case. The only thing close to what I want, was manual looping through the array, but I was wondering if there was a more efficient way, because this code will be executed arround 500.000 times, so speed is important!
Is there a efficient way to determine those values?
This answer based on #Mark Tolonen hint about bisect
Let's say that you need to append one number on every iteration but initial array is the same.
All elements in array should be unique. Initial array may be not sorted.
import bisect as b
init_array = [5, 9, 10, 11, 14, 15, 1, 7]
init_array.sort()
numbers_to_append = [22, 4, 12, 88, 99, 109, 999, 1000, 1001]
numbers_to_check = [12, 55, 23, 55, 0, 55, 10, 999]
for (_, n) in enumerate(numbers_to_check):
# get index of closer right to below
i = b.bisect_left(init_array, n)
# get above
if i >= (len(init_array)):
above = None
else:
if init_array[i] == n:
try:
above = init_array[i + 1]
except IndexError:
above = None
else:
above = init_array[i]
# get below
below = init_array[i - 1] if i - 1 >= 0 and init_array[i - 1] - n < 0 else None
print('---------')
print('array is', init_array)
print('given x is', n)
print('below is', below)
print('above is', above)
print('appending', numbers_to_append[_])
# check if number trying to append doesn't exists in array
# WARNING: this check may be slow and added only for showing that we need to add only unique numbers
# real check should be based on real conditions and numbers that we suppose to add
i_to_append = b.bisect_left(init_array, numbers_to_append[_])
if numbers_to_append[_] not in init_array[i_to_append:i_to_append+1]:
init_array.insert(i_to_append, numbers_to_append[_])
output:
---------
array is [1, 5, 7, 9, 10, 11, 14, 15]
given x is 12
below is 11
above is 14
appending 22
---------
array is [1, 5, 7, 9, 10, 11, 14, 15, 22]
given x is 55
below is 22
above is None
appending 4
---------
array is [1, 4, 5, 7, 9, 10, 11, 14, 15, 22]
given x is 23
below is 22
above is None
appending 12
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22]
given x is 55
below is 22
above is None
appending 88
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88]
given x is 0
below is None
above is 1
appending 99
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99]
given x is 55
below is 22
above is 88
appending 109
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99, 109]
given x is 10
below is 9
above is 11
appending 999
---------
array is [1, 4, 5, 7, 9, 10, 11, 12, 14, 15, 22, 88, 99, 109, 999]
given x is 999
below is 109
above is None
appending 1000
Assuming that your array is not sorted, you will be indeed forced to scan the entire array.
But if it is sorted you can use a binary search approach that will run in O(log(n)), something like this:
def search_nearest_elems(array, elem):
"""
Uses dichotomic search approach.
Runs in O(log(n)), with n = len(array)
"""
i = len(array) // 2
left, right = 0, len(array) - 1
while right - left > 1:
if array[i] == elem:
return elem, elem
elif array[i] > elem:
right, i = i, (left + i) // 2
else:
left, i = i, (right + i) // 2
return array[left], array[right]
array = [1, 5, 7, 9, 10, 11, 14, 15]
assert search_nearest_elems(array, 8) == (7, 9)
assert search_nearest_elems(array, 9) == (9, 9)
assert search_nearest_elems(array, 14.5) == (14, 15)
assert search_nearest_elems(array, 2) == (1, 5)
import bisect
def find_nearest(arr,value):
arr.sort()
idx = bisect.bisect_left(arr, value)
if idx == 0:
return None, arr[idx]
elif idx == len(arr):
return arr[idx - 1], None
elif arr[idx] == value:
return arr[idx], arr[idx]
else:
return arr[idx - 1], arr[idx]
array = [1, 5, 7, 9, 10, 11, 14, 15]
print(find_nearest(array, 0))
print(find_nearest(array, 4))
print(find_nearest(array, 8))
print(find_nearest(array, 10))
print(find_nearest(array, 20))
Output:
(None, 1)
(1, 5)
(7, 9)
(10, 10)
(15, None)
Helper source
I'm trying to add only the prime numbers from my first list into a second list.
I'm not receiving any output.
li1= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
li2=[]
def is_primeList(lst):
pos = 2
for i in range(len(lst)):
x = True
if(i<2):
x = False
for j in range(2, i):
if i% j == 0:
x = False
break
if x:
li2.insert(i + pos, li1[i])
else:
print("Not prime")
is_primeList(li1)
for element in li2:
print(element)
It returns:
li1= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
li2=[]
def is_primeList(lst):
pos = 2
for i in range(len(lst)):
x = True
if(i<2):
x = False
else:
for j in range(2, i):
if i% j == 0:
x = False
break
if x:
li2.insert(i + pos, li1[i])
else:
print("Not prime")
is_primeList(li1)
for element in li2:
print(element)
In your code the if statement is outside the for so it will never execute in the proper way, kindly indent the code right
li1= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
_prime_list = li1[2:3]
def is_primeList():
for _i in li1[3:]:
# print _i,
_is_prime = [_i % _n == 0 for _n in _prime_list]
# print _is_prime
if not any(_is_prime):
_prime_list.append(_i)
is_primeList()
print _prime_list
Outputs
[2, 3, 5, 7, 11, 13, 17, 19]
You have bugs in your code. Please use this example as a starting point
I have a 2D array of integer value:
[[26, 9, 24, 13],
[16, 14, 39, 29]]
I need to select the number >= 14, ends in 9 or 4, and not 39. It returns 1 if the criteria meets, otherwise return 0, i.e.
[[0, 0, 1,0],
[0,0,0,1]]
updated: code suggested by Tomothy32
result = result = [[int(x >= 14 and x % 10 in (4, 9) and x != 19) for x in sl] for sl in X]
another nested loop approach
def test(X):
out = [[0]*len(X[0]) for _ in range(len(X))]
for i in range(len(X)):
for j in range(len(X[i])):
check = X[i][j]
if check>=14 and check%5==4 and check!=39:
out[i][j] = 2
return out
You can use a list comprehension:
x = [[26, 9, 43, 13],
[16, 14, 39, 29]]
result = [[int(x >= 14 and x % 10 == 9 and x != 39) for x in sl] for sl in x]
print(result)
# [[0, 0, 0, 0], [0, 0, 0, 1]]
To get the last digit, use the remainder/modulo operator.
Change this statements:
if element >=14 and element !=39:
to
if element >=14 and element !=39 and element%10==9:
An n-by-n square matrix (table of numbers) is a magic matrix if the sum of its row and the sum of each column are identical. For example, the 4-by-4 matrix below is a magic matrix. The sum of every row and the sum of every column are exactly the same value 34.
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
Write a function that takes a 4-by-4 matrix as an argument and then determine if the matrix is magic or not. The
#matrix should be stored as a two-dimensional list. Test your function with a magic matrix and a none magic matrix.
def magic(matrix = []):
magic_matrix = False
if len(matrix) != 4:
print('Enter a 4 * 4 matrix')
return magic_matrix
row1Sum = sum(matrix[0])
rowSum_ok = True
for row in range(1, 4):
if sum(matrix[row]) != row1Sum:
rowSum_ok = False
break
colSum_ok = True
for col in range(4):
s_col = 0
for row in range(4):
s_col += matrix[row][col]
if s_col != row1Sum:
colSum_ok = False
break
if rowSum_ok and colSum_ok:
magic_matrix = True
return magic_matrix
def mainMagic():
m1 = [[9, 6, 3, 16],
[4, 15, 10, 5],
[14, 1, 8, 11],
[7, 12, 13, 2]]
print('\nThe matrix:')
for i in range(4):
for j in m1[i]:
print(str(j).rjust(3), end =' ')
print()
if magic(m1):
print('is a magic matrix.')
else:
print('is not a magic matrix.')
m2 = [[6, 22, 44, 18],
[1, 11, 10, 13],
[3, 17, 6, 12],
[9, 14, 2, 1]]
print('\nThe matrix:')
for i in range(4):
for j in m2[i]:
print(repr(j).rjust(3), end = ' ')
print()
if magic(m2):
print('is a magic matrix.')
else:
print('is not a magic matrix.')
mainMagic()
With a couple of set comprehensions and a zip() that is fairly straight forward to cleanup like:
Code:
def is_magic(matrix):
sum_rows = {sum(row) for row in matrix}
sum_cols = {sum(col) for col in zip(*matrix)}
return len(sum_cols) == 1 and sum_cols == sum_rows
Test Code:
m1 = [[9, 6, 3, 16],
[4, 15, 10, 5],
[14, 1, 8, 11],
[7, 12, 13, 2]]
m2 = [[6, 22, 44, 18],
[1, 11, 10, 13],
[3, 17, 6, 12],
[9, 14, 2, 1]]
print(is_magic(m1))
print(is_magic(m2))
Results:
True
False