Python: How can I turn every negative number into a zero? - python

I'm trying an exercise that wants me to return a new list that contains all the same elements except the negative numbers which are turned into zeros in the returned list.
I have used a for loop to loop through the parameter list and if the number is below 0, I would append it to a new list but times it by 0. However, I get weird outputs such as empty lists. For example, the code below should print:
[0, 0, 9, 0, 0, 34, 1]
[9, 34, 1]
[0, 0, 0]
Please stick to using list methods thanks.
The code:
def get_new_list_no_negs(num_list):
new_list = []
for i in range(len(num_list)):
if i < 0:
new_list.append(num_list[i] * 0)
return new_list
def main():
print("1.", get_new_list_no_negs([-3, -6, 9, 0, 0, 34, 1]))
print("2.", get_new_list_no_negs([9, 34, 1]))
print("3.", get_new_list_no_negs([-9, -34, -1]))
main()

This should do:
def get_new_list_no_negs(num_list):
return [max(num, 0) for num in num_list]
the max function is a python builtin that will return the largest between the passed numbers.

Try this
l = [-2, -1, 0, 1, 2]
# this
l = [i for i in l if i > 0 else 0]
# or
l = [max(i, 0) for i in l]

The enumerate() function adds a counter to an iterable.
So for each element in a cursor, a tuple is produced with (counter, element); the for loop binds that to row_number and row, respectively.
l = [-2, -1, 0, 1, 2]
for index, value in enumerate(l):
if value < 0:
l[index] = 0
print(l)
O/P:
[0, 0, 0, 1, 2]

Related

Unexpected Result

I am writing a program to sort array using this Minimum function but getting unexpected result
def Minimum(Arr,starting,ending):
small = 0
for i in range(starting,ending-1):
#if i+1 != ending:
if Arr[small] > Arr[i+1]:
small = i + 1
return small
x=[-5,-3,-4,0,2,3,1,324,321]
def Sort4(Arr):
for i in range(len(Arr)-1):
temp = Arr[i]
value = Minimum(Arr, i, len(Arr))
Arr[i] = Arr[value]
Arr[value] = temp
Sort4(x)
print(x)
Result:[324, -5, -3, -4, 0, 1, 2, 3, 321] but i want my results [-5,-4,-3,0,1,2,3,321,324] i don,t know why i am getting wrong result
Your minimum function doesn't function properly. You need to check for the minimum within the (starting, ending) subarray:
def Minimum(Arr, starting, ending):
small = starting # assume first element is the smallest
for i in range(starting, ending): # go through each index in range
if Arr[small] > Arr[i]: # compare with current smallest
small = i # update smallest if required
return small
Which makes the sort work properly:
x = [-5, -3, -4, 0, 2, 3, 1, 324, 321]
def Sort4(Arr):
for i in range(len(Arr) - 1):
temp = Arr[i]
value = Minimum(Arr, i, len(Arr))
Arr[i] = Arr[value]
Arr[value] = temp
Sort4(x)
print(x)
Result:
[-5, -4, -3, 0, 1, 2, 3, 321, 324]

finding possible entries in Sudoku empty cells

I have been packaging a script to calculate all possible entries in the empty cells of a sudoku game. While the algorithm to screen the vertical column and the horizontal row works, it seems that my script is not able to screen the relevant box where the empty cell is located.
The code that I am using is the following:
def possible(y,x,n):
global grid
for i in range(0,9):
if grid[y][i] == n:
return False
for i in range(0,9):
if grid[i][x] == n:
return False
x0 = (x//3)*3
y0 = (y//3)*3
for i in range(0,3):
for j in range(0,3):
if (grid[y0+i][x0+j] == n):
#print((x0+j),end=' ')
#print((y0+i),end=' ')
return False
list.append(y+1)
list.append(x+1)
list.append(n)
return True
It seems that there is some problem with the append procedure.....
Any assistance is welcome
My general comments:
Seems like you are trying to append to a list which might or might
not be defined outside of the possible() function (it's not in the supplied code).
However, as it is
not defined within the scope of that function, you generally can't
access it from the inside. Related read.)
Also you should change a variable name as
list is a built-in type of Python and it is not
recommended to use builtin types as variable
names unless you absolutely need to do so for some reason.
Generally it is not a best practice to use global variables.
My suggestion would be to move the gathering of possible
numbers outside of this function. Example:
def possible(grid: list[list[int]], num: int, pos: tuple[int, int]) -> bool:
# Check row
if num in grid[pos[0]]:
return False
# Check column
if num in [item[pos[1]] for item in grid]:
return False
# Check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y * 3, box_y * 3 + 3):
if num in grid[i][box_x * 3: box_x * 3 + 3] \
and (i, grid[i].index(num)) != pos:
return False
return True
Then run this 'cleaner' function in a for loop or list comprehension to collect possible numbers for a given position on the Sudoku grid.
For example (for cycle):
possible_values = []
for i in range(1,10):
if possible(grid, i, (x, y)):
possible_values.append(i)
Or this (list comprehension):
possible_values = [n for n in range(1,10) if possible(grid, n, (0, 2))]
In the Sudoku game world one call the "possible entries" of the empty cells, candidates or pencil-marks.
Here is how we can identify the candidates of the empty cells.
grid = [
[0, 0, 0, 6, 0, 8, 9, 1, 0],
[6, 0, 2, 0, 9, 0, 3, 4, 0],
[1, 9, 8, 3, 0, 0, 0, 6, 7],
[0, 5, 9, 0, 0, 0, 4, 2, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 1, 3, 0, 2, 0, 8, 0, 0],
[9, 6, 0, 5, 3, 7, 2, 8, 0],
[2, 0, 0, 4, 1, 0, 0, 3, 0],
[3, 4, 0, 2, 8, 0, 1, 7, 9],
]
candidates=bytearray(729)
def identifyCandidates():
for cell in range(81):
row,col=divmod(cell,9)
if grid[row][col] == 0 :
for kan in range(1,10):
if not clueInSector(cell, kan):
candidates[9*cell+(kan - 1)]=1
def clueInSector(cell, clue):
cellrow,cellcol = divmod(cell,9)
for col in range(9):
if (col != cellcol and grid[cellrow][col] == clue) :
return True
for row in range(9):
if (row != cellrow and grid[row][cellcol] == clue) :
return True
rowB = 3 * ((cellrow) // 3)
colB = 3 * ((cellcol) // 3)
for row in range (rowB,rowB + 3) :
for col in range(colB,colB +3) :
if (col != cellcol and row != cellrow and grid[row][col] == clue) :
return True
return False
Print of the 13 first cells:
cell:0 candidates: 5.
cell:1 candidates: 3.7.
cell:2 candidates: 4.5.7.
cell:3 no candidate.
cell:4 candidates: 4.5.7.
cell:5 no candidate.
cell:6 no candidate.
cell:7 no candidate.
cell:8 candidates: 2.5.
cell:9 no candidate.
cell:10 candidates: 7.
cell:11 no candidate.
cell:12 candidates: 1.7.

remove zeros between values of a list

I have a list of list and I want to remove zero values that are between numbers in each list. All my lists inside my list have same lenght.
For example:
List1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
desired output:
list2=[[0,1,2,3,0,0],[0,5,6,9,0]]
I was thinking about using indices to identify the first non zero value and last non zero value, but then I don't know how I can remove zeros between them.
You have the right idea, I think, with finding the first and last indices of nonzeroes and removing zeroes between them. Here's a function that does that:
def remove_enclosed_zeroes(lst):
try:
first_nonzero = next(
i
for (i, e) in enumerate(lst)
if e != 0
)
last_nonzero = next(
len(lst) - i - 1
for (i, e) in enumerate(reversed(lst))
if e != 0
)
except StopIteration:
return lst[:]
return lst[:first_nonzero] + \
[e for e in lst[first_nonzero:last_nonzero] if e != 0] + \
lst[last_nonzero:]
list1 = [[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
list2 = [remove_enclosed_zeroes(sublist) for sublist in list1]
# [[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
Inspired by #python_user I thought about this a bit more and came up with this simpler solution:
def remove_internal_zeros(lst):
return [v for i, v in enumerate(lst) if v or not any(lst[i+1:]) or not any(lst[:i])]
This works by passing any value from the original list which is either
not zero (v); or
zero and not preceded by a non-zero value (not any(lst[:i])); or
zero and not followed by a non-zero value (not any(lst[i+1:]))
It can also be written as a list comprehension:
list2 = [[v for i, v in enumerate(lst) if v or not any(lst[:i]) or not any(lst[i+1:])] for lst in list1]
Original Answer
Here's another brute force approach, this pops all the zeros off either end of the list into start and end lists, then filters the balance of the list for non-zero values:
def remove_internal_zeros(l):
start_zeros = []
# get starting zeros
v = l.pop(0)
while v == 0 and len(l) > 0:
start_zeros.append(0)
v = l.pop(0)
if len(l) == 0:
return start_zeros + [v]
l = [v] + l
# get ending zeros
end_zeros = []
v = l.pop()
while v == 0 and len(l) > 0:
end_zeros.append(0)
v = l.pop()
# filter balance of list
if len(l) == 0:
return start_zeros + [v] + end_zeros
return start_zeros + list(filter(bool, l)) + [v] + end_zeros
print(remove_internal_zeros([0,1,0,2,3,0,0]))
print(remove_internal_zeros([0,5,6,0,0,9,0]))
print(remove_internal_zeros([0,0]))
print(remove_internal_zeros([0,5,0]))
Output:
[0, 1, 2, 3, 0, 0]
[0, 5, 6, 9, 0]
[0, 0]
[0, 5, 0]
I think this has to be done with brute force.
new = []
for sub in List1:
# Find last non-zero.
for j in range(len(sub)):
if sub[-1-j]:
lastnonzero = len(sub)-j
break
print(j)
newsub = []
firstnonzero = False
for i,j in enumerate(sub):
if j:
firstnonzero = True
newsub.append(j)
elif i >= lastnonzero or not firstnonzero:
newsub.append(j)
new.append(newsub)
print(new)
Please try this, remove all 0 between numbers in each list.:
list1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
rowIndex=len(list1) # count of rows
colIndex=len(list1[0]) # count of columns
for i in range(0, rowIndex):
noZeroFirstIndex = 1
noZeroLastIndex = colIndex - 2
for j in range(1, colIndex - 1):
if(list1[i][j] != 0):
noZeroFirstIndex = j
break
for j in range(colIndex -2, 0, -1):
if(list1[i][j] != 0):
noZeroLastIndex = j
break
for j in range(noZeroLastIndex, noZeroFirstIndex, -1):
if(list1[i][j] == 0 ):
del list1[i][j]
print(list1)
Result:
[[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
I wrote a pretty straight-forward approach. Try this.
def removeInnerZeroes(list):
listHold=[]
listNew = []
firstNonZeroFound = False
for item in list:
if item==0:
if firstNonZeroFound:
listHold.append(item)
else:
listNew.append(item)
else:
firstNonZeroFound=True
listHold.clear()
listNew.append(item)
listNew.extend(listHold)
return listNew
complexList = [[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
print(complexList)
complexListNew = []
for listi in complexList:
complexListNew.append(removeInnerZeroes(listi))
print(complexListNew)
One way to do it is to treat each sublist as 3 sections:
Zeros at the front, if any
Zeros at the end, if any
Numbers in the middle from which zeros are to be purged
itertools.takewhile is handy for the front and end bits.
from itertools import takewhile
List1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
def purge_middle_zeros(numbers):
is_zero = lambda x: x==0
leading_zeros = list(takewhile(is_zero, numbers))
n_lead = len(leading_zeros)
trailing_zeros = list(takewhile(is_zero, reversed(numbers[n_lead:])))
n_trail = len(trailing_zeros)
mid_numbers = numbers[n_lead:-n_trail] if n_trail else numbers[n_lead:]
mid_non_zeros = [x for x in mid_numbers if x]
return leading_zeros + mid_non_zeros + trailing_zeros
list2 = [purge_middle_zeros(sub_list) for sub_list in List1]
list2
[[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
Other notes:
the lambda function is_zero tells takewhile what the criteria are for continuing, in this case "keep taking while it's a zero"
for the mid_non_zeros section the list comprehension [x for.... ] takes all the numbers except for the zeros (the if x at the end applies the filter)
slicing notation to pick out the middle of the list, numbers[from_start:-from_end] with the negative -from_end meaning 'except for this many elements at the end'. The case where there are no trailing zeros requires a different slice expression, i.e. numbers[from_start:]
I wrote the following code out of curiosity, that is somewhat intuitive and mimics a "looking item-by-item" approach.
def remove_zeros_inbetween(list_):
new_list = list_.copy()
for j, l in enumerate(list_): # loop through the inner lists
checking = False
start = end = None
i = 0
deleted = 0
while i < len(l): # loop through the values of an inner list
if l[i] == 0: # ignore
i += 1
continue
if l[i] != 0 and not checking: # non-zero value found
checking = True # start checking for zeros
start = i
elif l[i] != 0 and checking: # if got here and checking, the finish checking
checking = False
end = i
if start and end: # if both values have been set, i.e, different to None
# delete values in-between
new_list[j] = new_list[j][:(start+1-deleted)] + new_list[j][(end-deleted):]
deleted += end - start - 1
if l[i] != 0: # for the case of two non-zero values
start = i
checking = True
else:
i = end # ignore everything up to end
end = None # restart check
i += 1
return new_list
>>> remove_zeros_inbetween([[0, 1, 0, 2, 3, 0, 5], [0, 5, 6, 0, 0, 9, 4]])
[[0, 1, 2, 3, 5], [0, 5, 6, 9, 4]]
>>> remove_zeros_inbetween([[0, 0], [0, 3, 0], [0]]))
[[0, 0], [0, 3, 0], [0]]
>>> remove_zeros_inbetween([[0, 0, 0, 0]]))
[[0, 0, 0, 0]]
You start by replacing 0 by "0" - which is not necessary. Secondly your filter call does not save the resulting list; try:
list1[i] = list(filter(lambda a: a !=0, list1[1:-1])) # changed indexing , I suppose this could work

How to sort array numbers by absolute value [duplicate]

This question already has answers here:
Sorting by absolute value without changing to absolute value
(3 answers)
Closed 3 years ago.
Given an array of ints:
(-20, -5, 10, 15)
the program should output:
[-5, 10, 15, -20]
I first tried to think about the pseudocode:
for each element in the array
if its absolute value is higher than the nxt element
swap them
And I implemented this as:
def sort_by_abs(numbers_array: tuple) -> list:
numbers_array = list(numbers_array)
for i, number in enumerate(numbers_array):
if i == len(numbers_array) - 1:
break
elif abs(number) > abs(numbers_array[i+1]):
temp = number
numbers_array[i] = numbers_array[i+1]
numbers_array[i+1] = temp
return numbers_array
However it fails when we have the following sequence:
(1, 2, 3, 0)
it outputs
[1, 2, 0, 3]
And I understand that when the element which needs to be moved is not at first there could be other numbers to be moved to the left
Then I tried sorting the list first, and it solves this case:
def sort_by_abs(numbers_array: tuple) -> list:
numbers_array = sorted(list(numbers_array))
for i, number in enumerate(numbers_array):
if i == len(numbers_array) - 1:
break
elif abs(number) > abs(numbers_array[i+1]):
temp = number
numbers_array[i] = numbers_array[i+1]
numbers_array[i+1] = temp
return numbers_array
However when we have: (-1, -2, -3, 0) it outputs [-2, -1, 0, -3] and it should return [0, -1, -2, -3]
How could be it improved?
Just use python builtin sorted with key abs which sorts considering the absolute value of the integer
def sort_by_abs(numbers_array):
return sorted(tuple(numbers_array), key=abs)
print(sort_by_abs((-5, 10, 15, -20)))
print(sort_by_abs((-1, -2, -3, 0)))
print(sort_by_abs((1, 2, 3, 0)))
The output will be
[-5, 10, 15, -20]
[0, -1, -2, -3]
[0, 1, 2, 3]

for loop that replaces element based on its value

I have a list of integers and I am trying to define a function which loops through every element to check if they are less than 5 and returns the list in string according to their contents.
intlist=[12, 10, 11, 23, 25, 2]
def clear(x):
for i in x:
if i < 5:
x[i] = 0
return str(x)
else:
return str(x)
print clear(intlist)
My code is not working as intended, could anyone enlighten me?
If they are, I am to change all elements in the list to '0'. The outcome should look something like this.
intlist=[0, 0, 0, 0, 0, 0]
However if none of the elements are less than 5, the output should remain the same.
intlist=[12, 10, 11, 23, 25, 2]
Welcome to StackOverflow! Your code has some logic problem. Here's my fix:
intlist=[12, 10, 11, 23, 25, 2]
def clear(x):
for i in x:
if i < 5: # If this is satisfied once, return string with n times of '0'
x = [0]*len(x) # This creates a list of zeros with same length as before
return str(x)
return str(x)
print clear(intlist)
Besides, in your example the element 2 is less than 5, so the output should be 000000
intlist=[12, 10, 11, 23, 25, 2]
def clear(x):
if (any(i<5 for i in intlist)): return [0]*len(intlist)
else: return(x)
print(clear(intlist)) # [0, 0, 0, 0, 0, 0]
check for the any item is <5 then return all zeros or keep the list as it is.
There are a couple of mistakes in the for loop that you have written. First, the return statement is inside the loop, which makes it exit just after the if statement or else statement, whichever it goes to first. Secondly, you are making a mistake with how you are indexing. If you wish to access elements through index, you range in your loop instead. Here is the correct implementation for the function that you want :
def clear(x):
for i in range(len(x)):
if x[i]<5:
x[i]=0
return str(x)
You can do it one one-line, creating a list of zeros if any one of the elements in list is less than 5 or retaining the list otherwise.
intlist = [12, 10, 11, 23, 25, 2]
intlist = [0] * len(intlist) if any(x < 5 for x in intlist) else intlist
print(intlist)
# [0, 0, 0, 0, 0, 0]

Categories