Compare multidimensional array in python - python
I have a multidimensional array called old_arr which is like this [[8,8,8,8,0,0,0,0,6,6,5,5],[...]] then I have an updated multidimensional array new_arr like this [[9,9,6,7,3,6,5,0,6,4,3,4],[...]] What I want to do is to update the new_arr so that if the value in it corresponds to a 0 in old_arr then the value should be 0 otherwise keep the new value. So in the above example the new_arr would look like this [[9,9,6,7,0,0,0,0,6,4,3,4],[...]] where the 3,6,5 where replaced by 0. Any advice?
Also I want to know if it is possible to update the cell to 0 only if 4 out of it's 8 surrounding neighbour cells have the value 0 as well? Like new_arr and old_arr are multidimensional array (lists) which represents rows and cols so they are like a big table as shown in the below image where the blue cell in the new_arr will only be updated to zero if the corresponding cell in the old_arr is 0 and 4 of its neighbour cells are 0 (white cells in the photo)
So I need to check all 8neighbour cells (sometimes 6 or 7 depending on the cell position where it's in the middle (8) or edges(7) or corners (6) ) if they are zeros or not and count them, if the count is 4 or more then set the cell value to 0.
So if old_arr is
[[8,8,8,8,0,0,0,0,6,6,5,5],
[8,8,8,8,0,x,0,0,6,6,5,5],
[8,8,8,8,0,0,0,0,6,6,5,5],
[8,8,8,8,0,0,0,0,6,6,5,5],....]
Where x is a zero
And new_arr is
[[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],....]
For the highlighted cell, the corresponding cell in the new_arr will be zero because the highlighted cell in old_arr is 0 and more than 4 of its neighbor cells are zeros as well.
Updated new_arr is
[[9,9,6,7,3,0,0,0,6,4,3,4],
[9,9,6,7,0,0,0,0,6,4,3,4],
[9,9,6,7,0,0,0,0,6,4,3,4],
[9,9,6,7,0,0,0,0,6,4,3,4],....]
Assuming old_arr and new_arr are the same length, you could do something like this:
old_arr = [[8,8,8,8,0,0,0,0,6,6,5,5], [8,8,7,0,0,0,0,0,6,6,5,5]]
new_arr = [[9,9,6,7,3,6,5,0,6,4,3,4], [9,0,6,7,4,6,5,0,6,4,3,4]]
new_arr = [[x if old[i] else 0 for i, x in enumerate(new)] for old, new in zip(old_arr, new_arr)]
print(new_arr)
which outputs:
[[9, 9, 6, 7, 0, 0, 0, 0, 6, 4, 3, 4], [9, 0, 6, 0, 0, 0, 0, 0, 6, 4, 3, 4]]
UPDATE:
Here is a brute force solution that deals with neighbouring cells:
old_arr = [[8,8,8,8,0,0,0,0,6,6,5,5],
[8,8,8,8,0,0,0,0,6,6,5,5],
[8,8,8,8,0,0,0,0,6,6,5,5],
[8,8,8,8,0,0,0,0,6,6,5,5]]
new_arr = [[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4]]
def first_last(row, next_row, old, new):
for i in range(len(new[row])):
count = 0
if old[row][i] == 0:
if old[row][i-1] == 0:
count += 1
if old[row][i+1] == 0:
count += 1
if old[next_row][i] == 0:
count += 1
if old[next_row][i-1] == 0:
count += 1
if old[next_row][i+1] == 0:
count += 1
if count > 4:
new[row][i] = 0
def middle(old, new):
for i, l in enumerate(new[1:-1]):
for j in range(len(l)):
count = 0
if old[i][j] == 0:
if old[i][j-1] == 0:
count += 1
if old[i][j+1] == 0:
count += 1
if old[i-1][j] == 0:
count += 1
if old[i-1][j-1] == 0:
count += 1
if old[i-1][j+1] == 0:
count += 1
if old[i+1][j] == 0:
count += 1
if old[i+1][j-1] == 0:
count += 1
if old[i+1][j+1] == 0:
count += 1
if count > 4:
l[j] = 0
# first row
first_last(0, 1, old_arr, new_arr)
# middle rows
middle(old_arr, new_arr)
# last row
first_last(-1, -2, old_arr, new_arr)
print(new_arr)
Which Outputs:
[[9, 9, 6, 7, 3, 0, 0, 0, 6, 4, 3, 4],
[9, 9, 6, 7, 0, 0, 0, 0, 6, 4, 3, 4],
[9, 9, 6, 7, 0, 0, 0, 0, 6, 4, 3, 4],
[9, 9, 6, 7, 3, 0, 0, 0, 6, 4, 3, 4]]
Note: This could be made better, but you can optimize it to your liking.
A simple solution with a list comprehension:
>>> old_arr=[9,9,6,7,3,6,5,0,6,4,3,4]
>>> new_arr=[8,8,8,8,0,0,0,0,6,6,5,5]
>>> [new_arr[i] if old_arr[i] else 0 for i in range(len(new_arr))]
[9, 9, 6, 7, 0, 0, 0, 0, 6, 4, 3, 4]
Lists are modifiable sequences in Python so you can change them in place, which can make sense for large data sets. You can do that simply with 2 nested loops:
for i, l in enumerate(new_arr):
for j in range(len(l)):
if old_arr[i][j] == 0:
l[j] = 0
def custom_compare(list_old, list_new):
a=[]
for num, each_list_old in enumerate(list_old):
for num1,each_list_new_entry in enumerate(list_new[num]):
if each_list_old[num1] != 0:
a.append(each_list_new_entry)
else:
a.append(0)
list_new[num] = a
a=[]
print "Finally new_arr = ",list_new
Eg:
old_arr = [[8,8,8,8,0,0,0,0,6,6,5,5],[1,2,3,4,5,6,7,8]]
new_arr = [[9,9,6,7,3,6,5,0,6,4,3,4],[8,3,4,5,6,78,8,9]]
custom_compare(old_arr, new_arr)
Finally new_arr = [[9, 9, 6, 7, 0, 0, 0, 0, 6, 4, 3, 4], [8, 3, 4, 5, 6, 78, 8, 9]]
A simple approach would be something like this:
first=[[8,8,8,8,0,0,0,0,6,6,5,5],[8,8,8,8,0,0,0,0,6,6,5,5],[8,8,8,8,0,0,0,0,6,6,5,5],[8,8,8,8,0,0,0,0,6,6,5,5]]
second = [[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4],
[9,9,6,7,3,6,5,0,6,4,3,4]]
for first_1,second_1 in zip(first,second):
for index,value in enumerate(first_1):
if value==0:
try:
if first_1[index-1]==0 and first_1[index+1]==0:
second_1[index]=0
second_1[index-1]=0
second_1[index+1]=0
except IndexError:
pass
print(second)
output:
[[9 9 6 7 0 0 0 0 6 4 3 4]
[9 9 6 7 0 0 0 0 6 4 3 4]
[9 9 6 7 0 0 0 0 6 4 3 4]
[9 9 6 7 0 0 0 0 6 4 3 4]]
Related
How do I replace elements in two-dimensional array in python?
My task is to replace all the elements whose both indexes are odd with 1, and all the elements whose both indexes are even with -1.
You can replace elements by using a double index like: array[y][x] if array is list of lists. This is a example: array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] length = len(array) for y in range(length): for x in range(length): if y % 2 and x % 2: array[y][x] = 1 elif y % 2 == 0 and x % 2 == 0: array[y][x] = 0 print(array) This will output: [[0, 2, 0], [4, 1, 6], [0, 8, 0]]
Answer: for i in range(row): for j in range(col): if (i%2==0 and j%2==0): array[i][j] = -1 elif (i%2 and j%2): array[I][j] = 1 row => length of nested array col => length of the array
test = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] def replace(arr): for i in range(len(arr)): for j in range(len(arr)): if i % 2 and j % 2: # checks if both indexes are odd test[i][j] = 1 elif not i % 2 and not j % 2: # checks if both indexes are even test[i][j] = -1 return arr print(replace(test)) # [[-1, 2, -1], [4, 1, 6], [-1, 8, -1]]
Move Zeroes to the end of the string
I was just doing some leetcode but this blew my mind. class Solution: def moveZeroes(self, nums: List[int]) -> None: nums = [0, 1, 0, 3 ,12] k = 0 i=0 while i < len(nums): print(i) if nums[i] == 0: print('inside if=',i) print('before',nums) k += 1 print('removed',nums[i]) nums.remove(i) print('after',nums) else: i += 1 print('no change',nums) print('final',nums) for j in range (k): nums.append(0) print(nums) and the output is: 0 inside if= 0 before [0, 1, 0, 3, 12] element to be removed 0 after [1, 0, 3, 12] 0 no change [1, 0, 3, 12] ->1 ->inside if= 1 ->before [1, 0, 3, 12] ->element to be removed 0 ->after [0, 3, 12] 1 no change [0, 3, 12] 2 no change [0, 3, 12] final [0, 3, 12] [0, 3, 12, 0, 0] How can it remove element 1 if it can read that it has to remove 0?
So I got to know my dumb mistake. Actually remove() is used to remove the element that is mentioned. Like if I type remove(6)from a list a = [1,2,3,4,5,6]. it removes element 6, not the element that is at 6th position. so use pop() to do so.
Python create multi dimensional array of of normal array
I want to create a multi dimensional Array out of normal array. When there is a 0 in my start array i want to change the row number by 1. My start array looks like this: arr = [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9] My futre multi array should look like this: multi_arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] My code looks like this so far: multi_arr = [] end = len(arr) i = 0 #row j = 0 #column for h in range(end): if arr[h] != 0: j += 1 multi_arr[i][j]= arr[h] elif arr[i] != 0: i += 1 I always get a list index error with this code.
If you really want to work with lists, you dont need a column indexer. You can simply append the value to the correct list. multi_arr = [[]] # start with a nested list, since your vector doesnt start with a 0 endi = len(arr) i = 0 #row for h in range(endi): if arr[h] != 0: multi_arr[i].append(arr[h]) else: i += 1 multi_arr.insert(i,[]) # open new list output: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
This should do the job in a simpler way: arr = [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9] multi_arr = [] temp_arr = [] for h in arr: if h != 0: temp_arr.append(h) else: multi_arr.append(temp_arr) temp_arr = [] if h != 0: # Insert the last array it the last number wasn't 0 multi_arr.append(temp_arr) print(multi_arr)
This is happening because at the point where you are trying set multi_arr[i][j], it is still a 1-d array. You can verify this with a print statement or a debugger - like so: for h in range(end): if arr[h] != 0: print(multi_arr) j += 1 multi_arr[i][j]= arr[h] elif arr[i] != 0: i += 1 I would definitely try something more pythonic for what you are trying to accomplish, reading the elements into a temp array and appending that temp array to multi array. arr = [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9] multi_arr = [] temp_array = [] for item in arr: if item == 0: multi_arr.append(temp_array) temp_array = [] else: temp_array.append(item) multi_arr.append(temp_array) print(multi_arr)
You are declaring a 1D array and appending like 2D array One solution two your Problem is : arr=[1,2,3,4,5,6,7,8,9] multi_arr=[] end = len(arr) a = [] counter =0 for i in arr : if counter < 3 : a.append(i) counter += 1 else: multi_arr.append(a) a=[] counter = 0 a.append(i) counter += 1 multi_arr.append(a) print(multi_arr)
Here is a yield approach: def f(arr): res = [] for x in arr: if x == 0: yield res res = [] else: res.append(x) yield res list(f(arr)) #> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
A different approach for you: super simple and no loop. import numpy as np arr = [1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9] a = [i for i in arr if i] x = arr[arr!=0] + 1 np.array(a).reshape([-1, x]) Output: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) And if you need lists, just use np.array(a).reshape([x, y]).tolist() instead. One-liner: After converting your list to a numpy array a = np.array(arr): a[a!=0].reshape([-1, len(a) - np.count_nonzero(a)+1])
Finding the number of substrings which sum is equal to m
I'm trying some python and I got this: I have a string S='3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2' and m=9. I want to know how many substrings with with sum equals m there are. So with S and m above i whould get 7 as a result as: '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2' _'0,4,0,3,1,0,1,0'_____________ _'0,4,0,3,1,0,1'_______________ ___'4,0,3,1,0,1,0'_____________ ____'4,0,3,1,0,1'_______________ ____________________'0,0,5,0,4'_ ______________________'0,5,0,4'_ _______________________'5,0,4'_ Now, the code i came up with does something like that def es1(S,m): c = 0 M = 0 ls = StringToInt(S) for x in ls: i= ls.index(x) for y in ls[i+1:]: M = x + y if M == m: c += 1 M = 0 break if M > m: M = 0 break else: continue return c def StringToInt(ls): s = [int(x) for x in ls.split(',')] return s Where StringToInt obv gives me a list of int to work with. The thing I don't get is where my concept is wrong since es1 returns 3
You could use zip to progressively add numbers to a list of sums and count how many 9s you have at each pass: S = '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2' m = 9 numbers = list(map(int,S.split(","))) result = 0 sums = numbers for i in range(len(numbers)): result += sums.count(m) sums = [a+b for a,b in zip(sums,numbers[i+1:]) ] print(result) For a more "functional programming" approach, you can use accumulate from itertools: from itertools import accumulate numbers = list(map(int,S.split(","))) ranges = (numbers[i:] for i in range(len(numbers))) sums = (accumulate(r) for r in ranges) result = sum( list(s).count(m) for s in sums ) print(result) To explain how this works, let's first look at the content of ranges, which are substrings from each position up to the end of the list: [3, 0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [0, 1, 0, 1, 0, 0, 5, 0, 4, 2] [1, 0, 1, 0, 0, 5, 0, 4, 2] [0, 1, 0, 0, 5, 0, 4, 2] [1, 0, 0, 5, 0, 4, 2] [0, 0, 5, 0, 4, 2] [0, 5, 0, 4, 2] [5, 0, 4, 2] [0, 4, 2] [4, 2] [2] When we make a cumulative sum of the rows (sums), we obtain the total of values starting at the position defined by the row number and for a length defined by the column number. e.g. line 5, column 3 represents the sum of 3 values starting at the fifth position: [3, 3, 7, 7, 10, 11, 11, 12, 12, 13, 13, 13, 18, 18, 22, 24] [0, 4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21] [4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21] [0, 3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17] [3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17] [1, 1, 2, 2, 3, 3, 3, 8, 8, 12, 14] [0, 1, 1, 2, 2, 2, 7, 7, 11, 13] [1, 1, 2, 2, 2, 7, 7, 11, 13] [0, 1, 1, 1, 6, 6, 10, 12] [1, 1, 1, 6, 6, 10, 12] [0, 0, 5, 5, 9, 11] [0, 5, 5, 9, 11] [5, 5, 9, 11] [0, 4, 6] [4, 6] [2] In this triangular matrix each position corresponds to the sum of one of the possible substrings. We simply need to count the number of 9s in there to get the result. The above solutions will perform in O(N^2) time but, if you are concerned with performance, there is a way to obtain the result in O(N) time using a dictionary. Rather than build the whole sub arrays in the above logic, you could simply count the number of positions that add up to each sum. Then, for the sum at each position, go directly to a previous sum total that is exactly m less to get the number of substrings for that position. from itertools import accumulate from collections import Counter numbers = map(int,S.split(",")) result = 0 sums = Counter([0]) for s in accumulate(numbers): result += sums[s-m] sums[s] += 1 print(result) Note that all these solutions support negative numbers in the list as well as a negative or zero target.
As mentioned by others, your code only looks at sums of pairs of elements from the list. You need to look at sublists. Here is a O(n) complexity solution (i.e. it's efficient since it only scans though the list once): def es2(s, m): s = string_to_int(s) c = 0 # index of left of sub-list left = 0 # index of right of sub-list right = 0 # running total of sublist sum current_sum = 0 while True: # if the sub-list has the correct sum if current_sum == m: # add as many zeros on the end as works temp_current_sum = current_sum for temp_right in range(right, len(s) + 1): if temp_current_sum == m: c += 1 if temp_right<len(s): temp_current_sum += s[temp_right] else: break if current_sum >= m: # move the left end along and update running total current_sum -= s[left] left += 1 else: # move the right end along and update running total if right == len(s): # if the end of the list is reached, exit return c current_sum += s[right] right += 1 def string_to_int(ls): s = [int(x) for x in ls.split(',')] return s if __name__ == '__main__': print(es2('3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2', 9))
This is the code you are looking for man. i felt looking by position was better for this problem so I did it and it worked. def es1(S,m): c = 0 M = 0 ls = StringToInt(S) for i in range(0, len(ls)): M = 0 for x in range(i, len(ls)): M += ls[x] if M == m: c += 1 elif M >= m: break return c def StringToInt(ls): s = [int(x) for x in ls.split(',')] return s print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9)) OUTPUT: 7
Your code counts how many pairs of numbers there are in the String S which together give m while you actually want to test all possible substrings. You could do something like: numbers = [3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2] m = 9 c = 0 for i in range(len(numbers)): for j in range(len(numbers)-i): sum = 0 for k in numbers[i:i+j]: sum += k if sum == m: c += 1 print(c) Output: 7
EDIT! ->This Code is actually all possible subsets, not sublists. I am going to leave this here though in case this solution is helpful to anyone who visits this question. This code gets every solution. If you take a look in the function es1() the result variable is huge list of arrays with all the possible solutions. import itertools def es1(S,m): result = [seq for i in range(len(StringToInt(S)), 0, -1) for seq in itertools.combinations(StringToInt(S), i) if sum(seq) == m] return len(result) def StringToInt(ls): s = [int(x) for x in ls.split(',')] return s print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9)) OUTPUT: 4608 There are 4608 possible sets that add to the value 9.
s = "3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2" m = 9 sn = s.replace(",","+") # replace "," with "+" d = {} # create a dictionary # create list of strings: # s2 = ["3+0","0+4","4+0".............] # s3 = ["3+0+4","0+4+0","4+0+3".............] # . # . # . for n in range(2,len(s.split(","))): d["s%s"%n] = [sn[i:i+(2*n-1)] for i in range(0,len(sn),2)][:-n+1] # evaluate whether sum of individual lists equal to m or not, then find out how many such lists are there l = sum([eval(x)==m for y in d.values() for x in y] ) # remember we didnot add s1, i,e check whether individual string == m or not l = l+sum([x==m for x in s.split(",")]) print(l) 7
How to replace K-values of list by skipping 9 from startend
I have a number lets make it a list s = [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] and I have k = 4 What I want is to replace 4-values of list s with number 9 which dont have number 9. means at position 2 ,we have 9,so skip that and replace next one. Output should be like: [9,9,9,9,9,2,7,3,6,8,4,1,9,0,0,3,6,8] With this code I am unable to skip 9's in it: x= [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] k = 4 def elements_replaced(lst, new_element, indices): return [new_element if i in indices else e for i, e in enumerate(lst)] output = elements_replaced(x,9,range(k)) print output
you can try: >>> s = [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] >>> k = 4 >>> for index,number in enumerate(s): if k > 0: if number != 9: s[index] = 9 k = k-1 else : break >>> s [9, 9, 9, 9, 9, 2, 7, 3, 6, 8, 4, 1, 9, 0, 0, 3, 6, 8]
You can also use list comprehensions. This will get inefficient if your input list is large relative to the number of nines. from itertools import chain, repeat s = [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] nines = chain([9] * 4, repeat(None)) result = [x if x == 9 else next(nines) or x for x in s] print(result) # [9, 9, 9, 9, 9, 2, 7, 3, 6, 8, 4, 1, 9, 0, 0, 3, 6, 8]
x = [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] k = 4 a = 0 while k and a < len(x): if x[a] != 9: x[a] = 9 k -= 1 a += 1
x= [1,6,9,2,3,2,7,3,6,8,4,1,9,0,0,3,6,8] k = 4 def elements_replaced(lst, new_element, indices): for index, value in enumerate(lst): if index in indices and value != new_element: lst[index] = new_element return lst output = elements_replaced(x,9,range(k+1)) print (output)