Function to check if the row of a matrix contains only zeros - python

My intention was to create (without the use of any module) a function which would index all zero rows of a matrix inside a list, here is the code I developed:
def check0(self):
L = []
for i in range(0, self._m):
for j in range(0, self._n):
if self[i, j] == 0:
if i not in L:
L.append(i)
return L
However at this point the function indexes the row as soon that it detects a zero in it, and I do not manage to find an additional condition for this to stop. Would anyone please have a solution?

The problem with your code is that it would add a row if at least one element of the row is zero. This would be a solution:
def check0(self):
L = []
for i in range(0, self._m):
for j in range(0, self._n):
if self[i, j] != 0:
break
else:
L.append(i)
return L
Here I am using the for else statement. The else clause is executed if the break statement inside the for is not reached, which only happens if all elements of the row are zero.

Assuming your previous questions deal with the same matrix class, you seem to store the data in a list of lists. In that case you can simply do
def check0(self):
return [i for i, row in enumerate(self._matrix) if not any(row)]
0 has a falsy value, so any(list_of_only_zeros) will return False.
If you wanted to implement the any() functionality yourself, it'd look like the following
indices = []
for i, row in enumerate(self._matrix):
contains_nonzero = False
for elem in row:
if elem != 0:
contains_nonzero = True
break
if not contains_nonzero:
indices.append(i)
Which is similar to the for else suggestion from the other answer. In this case the for else is a bit more succinct, since it saves you two lines not having to toggle the contains_nonzero flag.

Related

Why swapping does not occur in below python code

def rev(n):
for i in range(int(len(n)//2)):
temp = n[i]
n[i] = n[len(n)-i-1]
n[len(n)-i-1] = temp
or,n[i], n[len(n)-i-1] = n[len(n)-i-1], n[i]
return n
n=[34,45,56,67]
print(rev(n))
Above code doesn't reverse the list even the logic is correct still the output is same as input.
Can anyone help me with that as i am little bit confused.
The intention appears to be to reverse the contents of a list in situ.
The most common way to do this is to create a new list with:
mylist[::-1]
...then... copy over the original like this:
mylist[:] = mylist[::-1]
However, the intent appears to be to use a custom loop to reverse in place.
def rev(_list):
i, j = 0, len(_list)
while (j := j - 1) > i:
_list[i], _list[j] = _list[j], _list[i]
i += 1
return _list
This demonstrates the correct element swap syntax and also obviates the need to create a new list. It is however very slow in comparison to traditional techniques

Adding two sum with recursion

Question: Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.Each input would have exactly one solution, and you may not use the same element twice. for example.
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Output: Because nums[0] + nums[1] == 9, we return [0, 1].
I'm trying one make a helper function that add the first number with each of the rest number, and run this helper function recursively on the give list nums. I'm not sure where my codes is wrong. (I know there are other more efficient algorithms, for the purpose of exercise pls stick to this approach)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# One function that takes a list, and find out first + i ==target, if exists
def help_(lst,tar):
for i, n in enumerate(lst[1:],start=1):
if lst[0]+n ==tar:
return i
else:
return False
ctn=0
#base case, if a sublist whose first num + another another is target
if help_(nums,target) != False:
return [0+ctn,help_(nums,target)+ctn] # return two indices from helper, adding the time it looped
else:
ctn =+1
return help_(nums[1:],target)
There are a few issues:
Your recursive call return help_(nums[1:],target) will not return a pair, but one index (or False), so this should never be returned in the main function. Instead make the recursive call on twoSum, which will return a pair (if successful). Then you will still need to add 1 to both indices before returning that.
The helper function is returning always in the first iteration of the loop. You should move the return False out of the loop's body.
It is a pity that you call the helper function twice with the same arguments. Just store the result in a temporary variable to avoid re-executing it
Here is your code with those corrections:
class Solution:
def twoSum(self, nums, target):
# One function that takes a list, and find out first + i ==target, if exists
def help_(lst,tar):
for i, n in enumerate(lst[1:],start=1):
if lst[0]+n ==tar:
return i
return False
ctn=0
res = help_(nums,target)
if res != False:
return [0+ctn, res+ctn]
else:
ctn =+1
x, y = self.twoSum(nums[1:], target)
return x+1, y+1
As you noted in your question this is not the most efficient way to solve this problem.
Using a dictionary leads to a better time complexity. In case you cannot find it, here is such a solution (spoiler):
d = { target - num: i for i, num in enumerate(nums)}`
return next((i, d[j]) for i, j in enumerate(nums) if j in d.keys() and i != d[j])
Your approach is globally valid (the implementation is not) but you have to keep track of a lot of parameters
The ideal is to only check the combinations:
nums = [2,7,11,15]
s = 9
from itertools import combinations
for (i,a),(j,b) in combinations(enumerate(nums), r=2):
if a+b == s:
print(i,j)
Output: 0 1
NB. I purposely proposed an answer with a module to give you the chance to rewrite it with a classical loop
for i in range(len(nums) - 1):
for j in range(i + 1, len(nums)):
total = nums[i] + nums[j]:
if total == target:
return nums[i], nums[j]

Python - Removing first two occurrences of element in list

The objective of this function is to remove the first two occurrences of n in a list.
Below is a code I had written but I still got it wrong after many hours. A friend advised me not to edit a list while iterating. However, I'm still stuck.
def remove_first_two(list,n):
if list == []:
return []
else:
count = 0
for ele in list:
if ele == n:
list.remove(ele)
count += 1
if count == 2:
break
return list
list = [1,2,2,3]
print(remove_first_two(list,2)) => [1,2,3] instead of [1,3]
Use list.remove twice with try-except. That will delete first two entries. Complexity O(n)
list_a = [1,2,3,4]
try:
list_a.remove(n)
list_a.remove(n)
# run a loop too, if it's more than 2
except:
pass
You can try find all indexes and del:
a = [1,2,3,2,3,2,4]
indices = [i for i, x in enumerate(a) if x == 2]
print(indices)
[1, 3, 5]
del a[indices[0]], a[indices[1]]
print(a)
[1, 3, 2, 2, 4]
First, don't use 'list' as its a key word in Python. Use something else, like 'alist'.
The code below does what you want and keeps the basic form of what you already have. You can of course also use the built-in .remove() method.
def remove_first_two(alist, n):
if alist == []:
return []
else:
count = 0
while count < 2:
for ele in alist:
if ele == n:
alist.remove(ele)
count += 1
return alist
alist = [1,2,2,3]
print(remove_first_two(alist,2)) # Output -> [1,3]
When your friend says "do not edit a list while iterating," he/she is right, and what he/she means is that you should create another list all together. What you are looking to do is the following:
def remove_first_two(list, n):
if list == []:
return []
else:
new_list = []
count = 0
for ele in list:
if ele == n:
if count >= 2:
new_list.append(ele)
count += 1
else:
new_list.append(ele)
return new_list
However, note that you can use use some built in functions to make your life much easier:
list.remove(x)
Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.
Therefore, you can more simply do:
def remove_first_two(list, n):
if list == []:
return []
for _ in range(2):
if n in list:
list.remove(n)
return list
Python updates the list if you change it while iterating.
In you test case with list = [1,2,2,3] when list[1] is deleted and Python updates list = [1,2,3]. Now Python understands you have iterated till index 1 and continues from index 2 which now contains 3. So Python encounters only one occurance of 2.
So heed your friends advice and do not edit list while iterating :)
Now you can use Python's in-built list.remove(element) to delete first ocuurence of a element. Repeat it 2 times for desired output.
Also O(n) with a single parse.
def remove_first_two(mylist,n):
counter = 0
def myfilter (i):
nonlocal counter,n
if counter > 2:
return True
else:
counter += 1
return (i != n)
return (list(filter(myfilter,mylist)))
This can also be done in python 3.8 using assignment expressions in a list comprehension:
data = [1,2,3,2,3,2,4]
count = 2
num = 2
[x for x in data if x != num or (count:=count-1) < 0]
Results:
[1, 3, 2, 2, 4]
Here is the reason why your program does not work:
When you remove an element, the for loop moves on to the next element, but by "moving on" it is actually skipping the element which now occupies the position of the deleted element. It skips the element right after the one you deleted.
The correct way to iterate over a list while you delete elements is making index progression explicit, by using a while loop instead of a for loop, and not increase the index when you delete an element:
i = 0
while i < len(my_list):
if condition:
my_list.pop(i)
else:
i += 1
However, none of this is necessary in your case! Notice that when you use my_list.remove(ele), you are not providing an index as you would with my_list.pop(i), so Python has to search for the first element that matches ele. Although remove will be slower than pop when used by themselves, here remove allows you not use any loops at all, simply do my_list.remove(n) twice!
Last touch: If your list has less than two elements matching n, one of the two my_list.remove(n) commands would return a ValueError. You can account for this exception, knowing that if it happens, your list is ready and requires no further action.
So the code you need is:
try:
my_list.remove(n)
my_list.remove(n)
except ValueError:
pass

PYTHON3: indentation of return values

This is working fine but I just don't get it why this works in this way. I think the return of True value should be inside the for loop but when I run this program it works in the opposite way.
Can someone point out what i am misunderstanding about the indentation of return values?
Even though the solution was even shorter I wanted to know exactly about my way of coding. Please help!
# My attempt
def palindrome(s):
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1):
if mylist[i] == mylist[j]:
i+=1
j-=1
continue
return False
return True
# Solution answer:
def palindrome(s):
return s == s[::-1]
When a function is called, the function can return only once.
This kind of return pattern is very frequently found across various programming languages. It is intuitive and efficient.
Let's say you have to check if a list of 1000 values contain only even numbers. You loop through the list and check if each element is even. Once you find an odd number, you do not need to go further. So you efficiently and immediately return and exit from the loop.
Here is hopefully a little bit more intuitive version of your code:
def palindrome(s):
l, r = -1, 0 # left, right
for _ in range(0, len(s) // 2 + 1): # more efficient
l += 1
r -= 1
if s[l] != s[r]:
return False
return True
Once you know the input is not palindrome, you do not need to go further.
If you did not need to stop, it is palindrome.
They follow the exact same rules as any other statement. What you have written means
def palindrome(s) {
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1) {
if mylist[i] == mylist[j] {
i+=1
j-=1
continue
}
return False
}
return True
}
# My attempt
def palindrome(s):
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1):
if mylist[i] == mylist[j]:
i+=1
j-=1
continue
return False
return True
In the above code what happens is inside the for loop each time it checks if there is a mismatch in the values by comparing values by iterating over the list forwards using variable "i" and backwards using variable "j". and returns false immediately if any one letter mismatches and so exits from the loop. And true is returned only once the for loop is completed which means no mismatch was found in the loop
Note: i=0 gives first index, i+=1 iterates forward and j=-1 gives last index, j-=1 iterates backward
Basically, when you index an array in numpy, you do it the way:
a[start:end:step]
,for every dimension. If step is negative, you return the values in inverse order. So, if step is -1, the array a[::-1] is the inverted array of a[::].
a[::-1] = a[::]
Then, if a sequence is the same as its inverse, by definition, it is a palindrome.
See:
https://www.geeksforgeeks.org/numpy-indexing/

Python how to skip the first (i.e. zero) iteration using enumerate and a list?

I have a table object.
I want to check to see if the first row has the value of Test, in which case I need to do something with each row in the table.
Otherwise, if the first row does not have the value of Test I need to skip that row and do something with rows 1 and on.
Because I need both the index and the row, I have to use enumerate, but it seems like I am using it in a messy way. Here I am calling enumerate twice and checking to see if the index is 0 twice. Is there a more concise way to to this?
for i, r in enumerate(null_clipData.rows()):
if r[0].val == 'Test':
# Do something if the first row is Test
for index, row in enumerate(null_clipData.rows()):
if index == 0:
continue # But do anything the first time (stay in this loop though)
print(index, row)
break # All through with test row
if i == 0:
continue # Don't do anything with the first row if the value was not Test
print(i, r) # Do something with i and r
Following Kevin’s advice, you can handle the first item separately, and then continue with the loop:
rows = iter(null_clipData.rows())
firstRow = next(rows)
specialHandling = firstRow.val == 'Test'
for i, r in enumerate(rows, start=1):
if specialHandling:
# do something special with r
else:
# do the normal stuff with r
Alternatively, you can also keep it in a single loop:
specialHandling = False # default case
for i, r in enumerate(null_clipData.rows()):
if i == 0: # first item
specialHandling = r == 'Test'
continue
if specialHandling:
# do something special with r
else:
# do the normal stuff with r
rows=null_clipData.rows()
enumeration=enumerate(rows[1:])
if rows[0]=='Test':
for idx,row in enumeration:
print(idx,row)
else:
for i,r in enumeration:
print (i,r)
Something like that?
I would suggest that you factor out the two different for loops into their own functions, to keep it cleaner.
just noticed Poke's answer, that too :)

Categories

Resources