Appending elements into list in a specific way - python

I have a task where I have to get a specific list. The task is that I get an input of a string, that only contains digits from 0-9. Now, we have to append those elements in a specific way. We need to cut the string, so that the groups are only 2 to 4 digits long. Groups should start with 0 only if they have to. Every string is 2 to 30 digits long.
I've managed to get the list where groups don't start with 0, but my groups are too big. This is where I am having trouble. How do I manage this groups that are only 2 to 4 digits long.
Some examples for input and output:
Input: 01365400606
My output: [0, 1, ' ', 3, 6, ' ', 5, 4, ' ', 0, 0, 6, 0, 6]
Desired Output: [0, 1, ' ', 3, 6, ' ', 5, 4, 0, 0, ' ', 6, 0, 6]
Example where group has to start with 0 because there are more than four times 0 appears.
Input: 011000000011000100111111101011
Desired output: [0, 1, " ", 1, 0, 0, 0, " ", 0, 0, 0, 0, " ", 1, 1, 0, " ", 0, 0, " ", 1, 0, 0, 1, " ", 1, 1, 1, 1, " ", 1, 1, 0, " ", 1, 0, 1, 1]
There are more correct solutions to each string, i.e. 01365400606, can be cut in a more ways:
0136 5400 606
01 36 5400 606
My code:
def NumberCutter(number):
count = 0
numberList = []
numberListSolution = []
for e in number:
e = int(e)
numberList.append(e)
for e in numberList:
count += 1
numberListSolution.append(e)
if count % 2 == 0 and e != 0:
numberListSolution.append(" ")
return numberListSolution

Try this:
def NumberCutter(number):
count = 0
# use list comprehensive more readable than for loop
numberList = [int(e) for e in number]
numberListSolution = []
def break_group():
""" add space and return 0 to reset the count."""
numberListSolution.append(' ')
return 0
# decision depends on the elements around current element we must know the index
for i, e in enumerate(numberList):
count += 1
numberListSolution.append(e)
if i == len(numberList) - 1:
continue # last element no need to add a space after it
if count == 2: # check for good decision when the count is two
# if you want to short the group that start with 0 to the minimum uncomment this
# but as you said priority to group length
# try:
# # 0e1AA == [0e 1AA] better than [0e1 AA]
# if not numberListSolution[-2] and numberList[i+1] and len(numberList) - i >= 2:
# numberListSolution.append(" ")
# count = 0
# except IndexError:
# pass
try:
# Pe100 --> Pe 100
if numberList[i+1] and not numberList[i+2] and not numberList[i+3] and len(numberList) - (i + 1) == 3:
count = break_group()
continue
except IndexError:
pass
try:
# Pe101 --> Pe 101
if numberList[i+1] and not numberList[i+2] and numberList[i+3] and len(numberList) - (i + 1) == 3:
count = break_group()
except IndexError:
pass
if count == 3: # check for good decision when the count is three
# if you want to short the group that start with 0 to the minimum uncomment this
# but as you said priority to group length
# try:
# # 0e1AA == [0e 1AA] better than [0e1 AA]
# if not numberListSolution[-3] and numberList[i+1] and len(numberList) - i >= 2:
# numberListSolution.append(" ")
# count = 0
# continue
# except IndexError:
# pass
try:
# PPeA1A --> PPeA 1A
if numberList[i+2] and (len(numberList) - (i + 1) >= 2):
# priority to group length
continue
except IndexError:
pass
try:
# PP0111 PPe 111
if not e and not numberList[i+1] and not numberList[i+2] and numberList[i+3]:
count = break_group()
continue
except IndexError:
pass
try:
# PPe1A... PPE 1A.... at least there is two element after e and the first element is not zero
# PPeAA] force PPE AA there is exactly two element force the break
if numberList[i + 1] and (len(numberList) - (i + 1) >= 2) or (len(numberList) - (i + 1) == 2):
count = break_group()
continue
except IndexError:
pass
# we have 4 element force the group
if count == 4:
count = break_group()
continue
return numberListSolution
print(NumberCutter('011000000011000100111111101011'))
# [0, 1, 1, 0, ' ', 0, 0, 0, 0, ' ', 0, 0, 1, ' ', 1, 0, 0, 0, ' ', 1, 0, 0, 1, ' ', 1, 1, 1, 1, ' ', 1, 1, 0, ' ', 1, 0, 1, 1]
print(NumberCutter('01365400606'))
# [0, 1, 3, 6, ' ', 5, 4, 0, 0, ' ', 6, 0, 6]
Note: in the comment I explained special cases to take a good decision with special letters:
P is a previous number >=0
e is the current element
A is number after the e >=0
when the previous number (P) or Next number (A) is noZero I use 1: like 1Pe1A1. and I use 0 for the inverse case 0PeA0AA
when e is 0 I use 0 like P0A

Related

How to find the max hotspot of a matrix in python

I was given a matrix question on a technical assessment that revolved around the idea of finding the "Max Hotspot".
Areas of connected 1's represent a hotspot, and given a matrix we want to return the max hotspot. Similar to "Number of Islands" or "Word Search.
areamap = [[1, 0, 0, 0],
[1, 1, 1, 0],
[0, 0, 0, 1],
[1, 1, 1, 1]]
areamap = [[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 0, 0, 0],
[1, 0, 0, 0]]
I tried using the 4 way DFS approach but had trouble creating/incrementing a variable that keeps track of the size of each hotspot. Any suggestions/help? Below is my attempt.
The idea of my algo is that every time we find a 1, we "evaporate" it to avoid traveling duplicates. For each 1 we evaporate, we incrementing the count of 1's. The count variable and the tmp list variable always print/return as empty.
class Solution:
def hotSpots(self, area: List[int]):
def evap(r, c, cnt):
if r < 0 or c < 0 or r >= len(area) or c >= len(area[0]) or area[r][c] == "0":
return
cnt += 1
area[r][c] = "0"
evap(r, c + 1)
evap(r, c - 1)
evap(r + 1, c)
evap(r - 1, c)
return
tmp = []
for i in range(len(area)):
for j in range(len(area[0])):
count = 0
if area[i][j] == "1":
evap(i, j, count)
tmp.append(count)
return sum(max(tmp))
There are two issues with the code:
evap does not return any result and so count never gets assigned anything other than 0
You have an array of integers, but you check its elements against strings ("0" and "1")
Solving those issues yields the following code, which outputs the result you want
def hotSpots(area):
def evap(r, c):
if r < 0 or c < 0 or r >= len(area) or c >= len(area[0]) or area[r][c] == 0:
return 0
area[r][c] = 0
return 1 + evap(r, c + 1) + evap(r, c - 1) + evap(r + 1, c) + evap(r - 1, c)
tmp = []
for i in range(len(area)):
for j in range(len(area[0])):
if area[i][j] == 1:
count = evap(i, j)
tmp.append(count)
return sum(max(tmp))

I am trying to create a sudoku solver, however I am stuck and cannot find the mistake

So I am trying to create a sudoku solver, however, I am stuck.
When the number reaches 10, it should go back one square and try again. However, when it reaches number 10, it suddenly goes to a negative row.
I have tried rewriting my code to see if anything would change due to a semantic error, however, it still doesn't work.
I would really appreciate if you could help me out.
Edited question / problem:
When it reaches number 10, it should change the variable direct to "back". Then when new_square is called, it should go one position back. But then for some reason, it infinitely goes back, until the row goes to the negative (position was 1 7, but it almost like recursion it goes back one column, until it goes into the minus row).
The code:
sudoku = [
# 0 1 2 3 4 5 6 7 8
[8, 0, 1, 0, 0, 0, 0, 4, 5], # 0
[0, 0, 0, 0, 0, 0, 7, 0, 6], # 1
[0, 5, 6, 0, 0, 0, 8, 0, 0], # 2
[0, 9, 0, 7, 0, 0, 1, 0, 0], # 3
[0, 0, 0, 0, 8, 0, 0, 0, 0], # 4
[0, 0, 0, 2, 0, 0, 5, 3, 8], # 5
[0, 0, 0, 0, 4, 0, 0, 8, 0], # 6
[4, 2, 7, 0, 0, 0, 0, 1, 0], # 7
[0, 0, 0, 0, 9, 0, 0, 0, 4] # 8
]
original = tuple(sudoku)
row = 0
column = 0
direct = "forw"
number = 0
steps = 0
game_change = True
def start():
global row, column, number, direct, steps
steps += 1
if not ((sudoku[row][column] == original[row][column]) and sudoku[row][column] != 0):
direct = "forw"
if number == 0:
number = 1
if number != 10:
direct = "forw"
rowc = row_check()
colc = column_check()
boxc = box_check()
if rowc and colc and boxc:
sudoku[row][column] = number
new_square()
number = sudoku[row][column]
else:
number += 1
else:
direct = "back"
new_square()
number = sudoku[row][column] + 1
return
else:
new_square()
number = sudoku[row][column] + 1
return
def row_check():
global row, number
if number not in sudoku[row]:
return True
else:
return False
def column_check():
global column, number
new_col = []
for i in range(9):
new_col.append(sudoku[i][column])
if number not in new_col:
return True
else:
return False
def box_check():
global row, column, number
srow = 0
scol = 0
if row in [0, 1, 2]:
srow = 0
elif row in [3, 4, 5]:
srow = 3
elif row in [6, 7, 8]:
srow = 6
if column in [0, 1, 2]:
scol = 0
elif column in [3, 4, 5]:
scol = 3
elif column in [6, 7, 8]:
scol = 6
new_box = []
for i in range(srow, (srow + 3)):
for j in range(scol, (scol + 3)):
new_box.append(sudoku[i][j])
if number not in new_box:
return True
else:
return False
def new_square():
global row, column, direct
if direct == "forw":
if column == 8:
column = 0
row += 1
else:
column += 1
else:
if column != 0:
column -= 1
else:
column = 8
row -= 1
while game_change:
start()
if steps % 1000 == 0:
print("It is done")
Answering the question
deepcopy
First up I noticed original = tuple(sudoku). This won't do. You are creating shallow copy but you want deepcopy. In short: if you edit a row in sudoku, the corresponding row in original will change as well.
To prevent that, use deep copy:
from copy import deepcopy
original = deepcopy(sudoku)
What now?
I tried to debug your code further. Mainly I added a few prints and a nice print_with_cursor function. I wasn't very successful, there is my code for future reference.
from copy import deepcopy
sudoku = [
# 0 1 2 3 4 5 6 7 8
[8, 0, 1, 0, 0, 0, 0, 4, 5], # 0
[0, 0, 0, 0, 0, 0, 7, 0, 6], # 1
[0, 5, 6, 0, 0, 0, 8, 0, 0], # 2
[0, 9, 0, 7, 0, 0, 1, 0, 0], # 3
[0, 0, 0, 0, 8, 0, 0, 0, 0], # 4
[0, 0, 0, 2, 0, 0, 5, 3, 8], # 5
[0, 0, 0, 0, 4, 0, 0, 8, 0], # 6
[4, 2, 7, 0, 0, 0, 0, 1, 0], # 7
[0, 0, 0, 0, 9, 0, 0, 0, 4] # 8
]
original = deepcopy(sudoku)
row = 0
column = 0
direct = "forw"
number = 0
steps = 0
game_change = True
def start(row, column, number, direct, steps):
steps += 1
print(f"row {row}, column {column}, number {number}", end="")
if not ((sudoku[row][column] == original[row][column]) and sudoku[row][column] != 0):
direct = "forw"
if number == 0:
number = 1
if number != 10:
direct = "forw"
rowc = number not in sudoku[row]
colc = column_check(column, number)
boxc = box_check(row, column, number)
if rowc and colc and boxc:
sudoku[row][column] = number
print(" set")
print_with_cursor(sudoku, row, column)
row, column = new_square(row, column, direct)
number = sudoku[row][column]
else:
if sudoku[row][column] != 0:
sudoku[row][column] = 0 # added
print(" reset")
print_with_cursor(sudoku, row, column)
number += 1
else:
direct = "back"
print(" unfillable")
print_with_cursor(sudoku, row, column)
row, column = new_square(row, column, direct)
number = sudoku[row][column] + 1
else:
row, column = new_square(row, column, direct)
number = sudoku[row][column] + 1
print()
return row, column, number, direct, steps
def print_with_cursor(sudoku, row, column):
print(f'{" "*column}v')
for irow, prow in enumerate(sudoku):
print(f'{"".join(str(p) for p in prow)}{"<" if irow == row else ""}')
def column_check(column, number):
new_col = []
for i in range(9):
new_col.append(sudoku[i][column])
return number not in new_col
def box_check(row, column, number):
if row in [0, 1, 2]:
srow = 0
elif row in [3, 4, 5]:
srow = 3
elif row in [6, 7, 8]:
srow = 6
if column in [0, 1, 2]:
scol = 0
elif column in [3, 4, 5]:
scol = 3
elif column in [6, 7, 8]:
scol = 6
new_box = []
for i in range(srow, (srow + 3)):
for j in range(scol, (scol + 3)):
new_box.append(sudoku[i][j])
return number not in new_box
def new_square(row, column, direct):
if direct == "forw":
if column == 8:
column = 0
row += 1
else:
column += 1
else:
if column != 0:
column -= 1
else:
column = 8
row -= 1
return row, column
while game_change:
row, column, number, direct, steps = start(row, column, number, direct, steps)
print("It is done")
The debug starts like this:
row 0, column 0, number 0
row 0, column 1, number 1
row 0, column 1, number 2
row 0, column 1, number 3 set
v
831000045<
000000706
056000800
090700100
000080000
000200538
000040080
427000010
000090004
row 0, column 2, number 1
row 0, column 3, number 1
row 0, column 3, number 2
row 0, column 3, number 3
row 0, column 3, number 4
row 0, column 3, number 5
row 0, column 3, number 6 set
v
831600045<
000000706
056000800
090700100
000080000
000200538
000040080
427000010
000090004
...
Code improvements
Let's upgrade your code! We can answer your question later, when the code is simpler to understand.
First up: fix SyntaxError
You are missing a code block after if steps % 1000 == 0:
while game_change:
start()
if steps % 1000 == 0:
print("It is done")
Secondly: get rid off global.
Then your code will be much more readable!
instead of
def new_square():
global row, column, direct
# do something
use
def new_square(row, column, direct):
# do something
return row, column
Then to call it, instead of
new_square()
use
row, column = new_square(row, column, direct)
Notice that now you get a much better idea of what the function does simply by looking at the call in the code.
Also: I am not a big fan of abbreviation direct of direction. I would rather see the whole word.
Bonus 1, inline function row_check:
def row_check():
global row, number
if number not in sudoku[row]:
return True
else:
return False
Can be simplified down to
def row_check():
global row, number
return number not in sudoku[row]
Note: use this simplification in all the X_check functions!
Now, this can be inlined, it is even used only in one place:
replace rowc = row_check()
by rowc = number not in sudoku[row]
Bonus 2, simplify X_check:
X_check's end with creating a list, checking if a number is in that list. Instead, we can iterate over what we are creating the list from and check whether the number is there. Maybe it is better understood with the solution:
create list of numbers in a sudoku box, then check if number is there
def box_check(row, column, number):
# setting srow & scol to be one of 0, 3, 6
new_box = []
for i in range(srow, (srow + 3)):
for j in range(scol, (scol + 3)):
new_box.append(sudoku[i][j])
return number not in new_box
check if number is in a sudoku box
def box_check(row, column, number):
# setting srow & scol to be one of 0, 3, 6
for i in range(srow, (srow + 3)):
for j in range(scol, (scol + 3)):
if number == sudoku[i][j]:
return False
return True
These two are the same, but the second doesn't use extra list, is simpler to understand. (And is more optimised, but that's not that important).
Do the same for column_check
Replace
def column_check(column, number):
new_col = []
for i in range(9):
new_col.append(sudoku[i][column])
return number not in new_col
with
def column_check(column, number):
for i in range(9):
if number == sudoku[i][column]:
return False
return True
We can go further there, replacing the range(9) by what is actually happening, we simplify it further to get:
def column_check(column, number):
for row in sudoku:
if number == row[column]:
return False
return True

How to reduce higher values to 1s and sort the ones from right to left

I want to make a python program that quickly reduces a number greater than 1 in an array/list and places it in an empty spot before it. Say we have:
li = [4,1,0,0,0,1,3,0]
we'd get:
rtr = [1,1,0,1,1,1,1,0]
Note how the 4 turns into a 1 because it's already to the left and then the 3 gets divided into 2 positions before the 1 that has already been taken. Can anyone help me with this problem?
You can iterate the list from end to start and keep track of the sum you collect from the values. When you have a non zero sum, take 1 from it to populate the result list, and otherwise put a 0 in the result list.
Here is how that could work:
def spread(lst):
carry = 0
res = []
for i in reversed(lst):
carry += i
res.append(int(carry > 0))
if carry:
carry -= 1
return list(reversed(res))
lst = [4, 1, 0, 0, 0, 1, 3, 0]
print(spread(lst)) # [1, 1, 0, 1, 1, 1, 1, 0]
Using numpy
def fun(l):
s = np.array(l[::-1])
for i in range(len(s)):
if s[i] != 1 and s[i] != 0:
x = s[i+1:]
x[(x == 0).nonzero()[0][:s[i]-1]] = 1
s[i] = 1
return s[::-1].tolist()
print (fun([4,1,0,0,0,1,3,0]))
print (fun([0, 10]))
Output:
[1, 1, 0, 1, 1, 1, 1, 0]
[1, 1]

how to compare 3 list value with If condition

Here are my lists
A = [32,33,34,35,36,37,38,39,40,41,42]
B = [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0]
C = [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
D = [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1]
Here, in list B value should be 0, in list C value should be 0 and in list D value should be 1
if this so then it is passed else failed.
As you can see in list B index 2 value is 1 so it is failed like this in list C index 1 value is 1 instead of 0 and in list D index 3,4 value is 2 instead of 1.
I've written the code for this but it is printing multiple time
I want to check the same index value for 3 list
like
B[0] = 0,B[1]=0
C[0] = 0,C[1]=1
D[0] = 1,D[1]=1
as you can see in first iteration values are correct but in 2nd time it get failed in C because 2nd index value is 1 instead of 0. like this way i want to check all 3 list.
for that reason I have taken the index from list A. you can see in my code.
my code-:
comment = "Wrong Signal in "
for first1 in A:
idx_val = A.index(first1)
if (B[idx_val] != 0):
comment = comment + 'B'
if C[idx_val] != 0:
comment = comment + 'C'
if D[idx_val] != 1:
comment = comment + 'D'
print comment
Output-'Wrong Signal in B,C,D,D,B
But i'm expecting the output like this
Output- 'Wrong Signal in B,C,D
and another example if B list's all value are zeros and C,D has wrong value in any index then it should print
output -'Wrong Signal in C,D
Thank You In Advance
for a, b, c, d in zip(A, B, C, D):
r = [
key for key, value, check in zip('bcd', (b, c, d), (0, 0, 1))
if value != check
]
if r:
print(f"{a}: wrong signal for {', '.join(r)}")
you can cast your lists to set and compare against one value:
def get_bad_list(lists, expected_values):
bad_lists = ''
for l, (s, v) in zip(lists, expected_values):
if set(l) != v:
bad_lists += s
return bad_lists
bad_lists = get_bad_list([B, C, D], [('B', {0}), ('C', {0}), ('D', {1})])
if bad_lists:
print 'Wrong Signal in ' + ', '.join(bad_lists) + '!'
else:
print 'All good!'
output:
Wrong Signal in B, C, D!
if you want to iterate over the lists and "to check the same index value" you can use:
comment = "Wrong Signal in "
is_B_good = True
is_C_good = True
is_D_good = True
for index in range(len(A)):
if is_B_good and B[index] != 0:
is_B_good = False
comment = comment + 'B '
if is_C_good and C[index] != 0:
is_C_good = False
comment = comment + 'C '
if is_D_good and D[index] != 1:
is_D_good = False
comment = comment + 'D '
print comment
output:
Wrong Signal in D C B
You need to exit your loop after you found the first instance. So you have to check if 0 is in B EVEN JUST ONCE. You can simply ask "if 0 in B". Then you can already quit, because you don't want to know how many times 0 is in B.
A = [32,33,34,35,36,37,38,39,40,41,42]
B = [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0]
C = [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
D = [1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1]
comment = "Wrong Signal in "
def check_if_fine(List,wrong_numbers,List_name):
No_repetitions = set(List)
for number in wrong_numbers:
if number not in No_repetitions:
return ''
else:
return List_name
comment += check_if_fine(B,[1],'B')
comment += check_if_fine(C,[1],'C')
comment += check_if_fine(D,[2],'D')
print(comment)

How to count specific elements before an element in a list?

We have a list
list = [1, 1, 1, 0, 1, 0, 0, 1]
I am trying find a function that would count the number of 0's before each item and then multiply this number by 3.
def formula(n):
for x in list:
if x == 1:
form = n * 3
return form
#If x is 1, count the number of zeros right before x and multiply this by 3,
For example for the list above, the first element is a 1 and there are no numbers right before it, the program should compute 0 * 3 = 0, for the second item, which is also a 1, the number right before it is also not a zero, the program should also compute 0 * 3 = 0. The 4th element is 0 so the program should ignore, For the 5th element which is a 1, the number right before it is a 0, the programme to compute 1 * 3 = 3, for the 6th element the number right before it is a 1, the system should compute 0 * 3 = 0. The 7th element is a 0, since x is not equal to 1 the program should not do anything. For the last element which is a 1, the last two numbers before it are zeros, the program should compute 2 * 3 = 6
I believe you are looking for a generator, with a simple counter:
def get_values (list):
n = 0
for x in list:
if x == 1:
yield n * 3
n = 0 # reset the counter
elif x == 0:
n += 1 # increment the counter
print(list(get_values([1, 1, 1, 0, 1, 0, 0, 1])))
# [0, 0, 0, 3, 6]
Try this,
def formula(l):
count_zero = 0
result = []
for i in l:
if i == 1:
result.append(3*count_zero)
count_zero = 0
elif i == 0:
count_zero += 1
return result
# Test case
l = [1, 1, 1, 0, 1, 0, 0, 1]
result = formula(l)
print(result)
# [0, 0, 0, 3, 6]
Here is my solution for the problem.
test_list = [1, 1, 1, 0, 1, 0, 0, 1]
def formula(list):
track = []
start = 0
for i,n in enumerate(list):
count_list_chunk = list[start:i]
if count_list_chunk.count(0) > 0 and n != 0:
start = i
if n != 0:
track.append( count_list_chunk.count(0)*3 )
return track
print formula(test_list)
#[ 0, 0, 0, 3, 6]

Categories