Change specific elements of a matrix puzzle - Python - python-3.x

I have to solve how to replace the elements below zero elements with zeros and output the sum of the remaining elements in the matrix.
For example, [[0,3,5],[3,4,0],[1,2,3]] should output the sum of 3 + 5 + 4 + 1 + 2, which is 15.
So far:
def matrixElementsSum(matrix):
out = 0
# locate the zeros' positions in array & replace element below
for i,j in enumerate(matrix):
for k,l in enumerate(j):
if l == 0:
break
out += l
return out
The code outputs seemingly random numbers.
Can someone fix what's wrong? Thanks

You can easily drop elements that are below a zero element is by using the zip function.
def matrixElementsSum(matrix):
out = 0
# locate the zeros' positions in array & replace element below
for i,j in enumerate(matrix):
# elements in the first row cannot be below a '0'
if i == 0:
out += sum(j)
else:
k = matrix[i-1]
for x, y in zip(j, k):
if y != 0:
out += x
return out
Now consider naming your variables a little more meaningfully. Something like:
def matrixElementsSum(matrix):
out = 0
# locate the zeros' positions in array & replace element below
for row_number, row in enumerate(matrix):
# elements in the first row cannot be below a '0'
if row_number == 0:
out += sum(row)
else:
row_above = matrix[row_number - 1]
for element, element_above in zip(row, row_above):
if element_above != 0:
out += element
return out
You should look into list comprehensions to make the code even more readable.

Related

Given a target, find the sum of the target from a list

Given a list of numbers and a target value, I am to find the sum of two numbers that matches the target and returns the indexes of the sum from the array.
I have tried:
nums = [2,5,5,11]
target = 10
def nums_sum_target(nums, target):
for i in range(len(nums)):
for j in range(len(nums)):
if j == len(nums) - 1:
target_sum = nums[i]
else:
print(j+1, "inner loop 2")
target_sum = nums[i] + nums[j+1]
if target_sum == target:
print([nums[i], nums[j+1]])
return [i, j+1]
I expected: [1,2]
I had: [1,1]
If the numbers are sorted, you can take advantage of that and just iterate from both ends like so:
def find_sum(numbers, target):
assert numbers # Should have at least 1 number
left = 0
right = len(numbers) - 1
while left < right:
total = numbers[left] + numbers[right]
if total == target:
return (left, right)
elif total < target:
left += 1
else:
right -= 1
raise LookupError(f"Sum {target} not found")
Testing the function:
numbers = [2, 3, 4, 5]
target = 6
indices = find_sum(numbers, target)
print(indices) # prints (0, 2)
No need for a dictionary or anything else, just the list and the target, and this is an extremely efficient way, with a worse case of O(n).

name 'count' is not defined in python

I have this code in python and I am trying to make a counter for the iteration of the binary search (yeah I know it is incomplete...), but I am stuck with the variable inside the function, when i try to print the variable count I get this error
name 'count' is not defined in python
can someone explain why i get this error?
import csv
def binarySearch(arr, l, r, x):
count=0
while l <= r:
mid = int(l + (r - l) / 2)
# Check if x is present at mid
if arr[mid] == x:
return mid
# If x is greater, ignore left half
elif arr[mid] < x:
l = mid + 1
# If x is smaller, ignore right half
else:
r = mid - 1
# If we reach here, then the element
# was not present
return -1
with open('bl_printed_music_500.csv', newline='', encoding="utf-8-sig") as csvfile:
reader = csv.DictReader(csvfile)
arr=[]
for row in reader:
if row ["Publication date (standardised)"] != "":
arr.append(int(row["Publication date (standardised)"])) #create list for searching
list.sort(arr) #list must be sorted to work
#print (arr)
x = 1850 #year to search
# Function call
result = binarySearch(arr, 0, len(arr) - 1, x)
found = False
if result != -1:
found = True
print(found)
print(count)
I think it's because you defined count in binarySearch but try to use it outside of the method. Try using a global variable (define it outside of binarySearch), it should work.
You can return count as well.
For example:
def myFunc():
x = 5
y = 10
return x,y
a, b = myFunc()
print(a)
print(b)
This will be:
5
10
Note that, I could have written x, y = myFunc(). These x and y are not the same as the ones inside myFunc(). The latter are local to the function.
In your code, you can return your local count variable:
return mid, count #(A)
return -1, count #(A)
And get its value by:
result, count = binarySearch(arr, 0, len(arr)-1, x) #(B)
Again, these two count variables, (A) and (B) are different variables with different scopes.
See, for instance:
https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
Alternatively, if a global variable, as suggested in the other answer, suits you best, you can see an example of its usage in the link.

counting number of pairs with same elem value in python list

I don't understand why the function is returning 4 while it should return 3. Thank you very much.
x = [10,20,20,10,10,30,50,10,20]
s = {}
count = 0
for item in x:
if (item in s):
s[item] += 1
else:
s[item] = 1
for z, w in s.items():
count += w/2
print(int(count))
From your description of what you said, of wanting to count pairs, then I believe you would want to round down the number being added to count instead of count overall, as 2 halves would end up making 1.
The following does return 3.
x = [10,20,20,10,10,30,50,10,20]
s = {}
count = 0
for item in x:
if (item in s):
s[item] += 1
else:
s[item] = 1
for z, w in s.items():
count += int(w/2)
print(count)
In Python, a single slash ”/“ does a regular divide that returns with decimals. A double slash “//“ returns a whole number rounded down. When you call int() on the number, it rounds it down to nearest whole number.
In your code, you get:
2+1.5+0.5+0.5=4.5
After calling int on 4.5, it becomes 4.
You are adding floats in the for loop, just change that to ints and it will add up to 3.
x = [10,20,20,10,10,30,50,10,20]
s = {}
count = 0
for item in x:
if (item in s):
s[item] += 1
else:
s[item] = 1
for z, w in s.items():
count += int(w/2)
print(int(count))

Creating a list of Primes and printing out the list in Python 3.6.1

I am trying to learn Python, but I'm still quite new at it. I am attempting to create a list of numbers from 2 up to the number that the user will input and go through the list and remove all non-prime numbers from that list, then print it back out. I am having trouble calculating since I keep getting the error: list index is out of range. I was thinking of using a for loop but then the variable i would be lower than variable current and I need to make sure i is always higher than current as it goes through the list. I am only allowed to use basic functions and loops for the task.
counter = 2
current = 2
n = int( input( "Please enter a number larger than 2. " ) )
while counter <= n:
userList.append( counter )
counter = counter + 1
print( "Printing out list " )
print( userList )
i = 1
while i <= len( userList ):
if userList[ i ] % current == 0:
userList.remove( userList[i] )
i = i + 1
else:
current = current + 1
print( userList )
There are some mistakes in your code.
1) Removing from large list is very slow, because you need to move everything after the item that was removed to avoid any gap between items in list. It's better to mark item as removed and then just print whatever left in there.
2) By using your algorithm, you need two while loops.
3) If you have got list with N items, than the last index of list is (N-1).
More Pythonic solution:
#!/usr/bin/env python3
n = int(input("Maximal number: "))
numbers = list(range(2, n+1))
i = 0
while i < len(numbers):
if numbers[i] != None:
j = i + 1
while j < len(numbers):
if numbers[j] != None:
if numbers[j] % numbers[i] == 0:
numbers[j] = None
j += 1
i += 1
print(list(filter(lambda x: x is not None, numbers)))`

'list index out of range' in while loop designed to return two values from list that adds to a specific sum

Line 11 produces the error. Stepping through the code doesn't reveal a problem?
The code just points at from left and right ends of list, moving pointers toward per iteration until a target sum is found or not! Doesn't look like the loops can step on itself but seems to anyway.
def twoSum(num_array, sum):
'''1.twoSum
Given an array of integers, return indices of the two numbers that
add up to a specific target.
'''
array = sorted(num_array)
l = array[0]
r = array[len(array)-1]
indx_Dict = dict(enumerate(array))
while (l < r) :
if (array[l] + array[r]) == sum:
return [indx_Dict[l], indx_Dict[r]]
elif array[l] + array[r] < sum:
l += 1
else:
r -= 1
num_array1 = [2, 7, 11, 15,1,0]
target1 = 9
twoSum(num_array1, target1)
that is what i changed:
array[len(array)-1] -> len(array)-1 (that's what caused your IndexError)
indx_Dict: i changed it such that indx_Dict[sorted_index] = original_index
sum -> sum_: sum is a built-in. it is never a good idea to use one of those as variable name! (yes, the new name could be better)
this is the final code:
def two_sum(num_array, sum_):
'''1.twoSum
Given an array of integers, return indices of the two numbers that
add up to a specific target.
'''
array = sorted(num_array)
l = 0
r = len(array)-1
indx_Dict = {array.index(val): index for index, val in enumerate(num_array)} ##
while (l < r) :
if (array[l] + array[r]) == sum_:
return [indx_Dict[l], indx_Dict[r]]
elif array[l] + array[r] < sum_:
l += 1
else:
r -= 1
here is a discussion about this problem:
Find 2 numbers in an unsorted array equal to a given sum (which you seem to be aware of - looks like what you are trying to do). this is a python version of just that:
def two_sum(lst, total):
sorted_lst = sorted(lst)
n = len(lst)
for i, val0 in enumerate(sorted_lst):
for j in range(n-1, i, -1):
val1 = sorted_lst[j]
s = val0 + val1
if s < total:
break
if s == total:
return sorted((lst.index(val0), lst.index(val1)))
return None
this version is based on looping over the indices i and j.
now here is a version that i feel is more pythonic (but maybe a little bit harder to understand; but it does the exact same as the one above). it ignores the index j completely as it is not really needed:
from itertools import islice
def two_sum(lst, total):
n = len(lst)
sorted_lst = sorted(lst)
for i, val0 in enumerate(sorted_lst):
for val1 in islice(reversed(sorted_lst), n-i):
s = val0 + val1
if s < total:
break
if s == total:
return sorted((lst.index(val0), lst.index(val1)))
return None
aaaaand just for the fun of it: whenever there is a sorted list in play i feel the need to use the bisect module. (a very rudimentary benchmark showed that this may perform better for n > 10'000'000; n being the length of the list. so maybe not worth it for all practical purposes...)
def two_sum_binary(lst, total):
n = len(lst)
sorted_lst = sorted(lst)
for i, val0 in enumerate(sorted_lst):
# binary search in sorted_lst[i:]
j = bisect_left(sorted_lst, total-val0, lo=i)
if j >= n:
continue
val1 = sorted_lst[j]
if val0 + val1 == total:
return sorted((lst.index(val0), lst.index(val1)))
else:
continue
return None
for (a bit more) completeness: there is a dictionary based approach:
def two_sum_dict(lst, total):
dct = {val: index for index, val in enumerate(lst)}
for i, val in enumerate(lst):
try:
return sorted((i, dct[total-val]))
except KeyError:
pass
return None
i hope the code serves as its own explanation...
l and r are not your indices, but values from your array.
Say you have an array: [21,22,23,23]. l is 21, r is 23; therefore, calling array[21] is out of bounds.
Additionally, you would have a problem with your indx_Dict. You call enumerate on it, which returns [(0,21),...(3,23)]. Calling dict gives you {0:21,1:22,2:23,3:23}. There is no key equivalent to 21 or 23, which will also give you an error.
What you could try is:
def twoSum(num_array, asum):
'''1.twoSum
Given an array of integers, return indices of the two numbers that
add up to a specific target.
'''
array = sorted(num_array)
l = 0
r = len(array)-1
while (l < len(array)-1) :
while (r > l):
if (array[l] + array[r]) == asum:
return [num_array.index(array[l]),\
num_array.index(array[r])]
r -= 1
r = len(array)-1
l += 1
num_array1 = [2, 7, 11, 15,1,0]
target1 = 9
twoSum(num_array1, target1)
This way, your l and r are both indices of the sorted array. It goes through every possible combination of values from the array, and returns when it either has found the sum or gone through everything. It then returns the index of the original num_array that contains the correct values.
Also, as #hiro-protagonist said, sum is a built-in function in Python already, so it should be changed to something else (asum in my example).

Resources