Create List with variable length in Python - python

testList= []
testList[12]= 31
testList[23]= 1337
Error: IndexError: list assignment index out of range
Basically I have unique Integers and I want to use the lists for a hash function h(x)= x (because they are unique)
I could initialize the length like this:
testList= [0 for i in range(50)]
But then I have to fix the size and my unique numbers which I have increase with time. Is it ok to set the size to for example 1-2Mio or is there a way to do this dynamically?
ArrayList<> in Java is dynamically for append and delete but so are Lists in Python also.
Thanks!

Perhaps you need a dict:
testList = {}
testList[12]= 31
testList[23]= 1337
print(testList)
print(testList[23])
Output:
{12: 31, 23: 1337}
1337

If you don't want to use a dictionary (which I do think you should do), you could create your own auto-extensible list:
class defaultlist(list):
def __init__(self,defData):
self.defData = defData
def _getDefault(self):
if isinstance(self.defData,type):
return self.defData()
return self.defData
def __getitem__(self,index):
if index >= len(self):
return self._getDefault()
return super.__getitem__(index)
def __setitem__(self,index,value):
while index>=len(self):
self.append(self._getDefault())
list.__setitem__(self,index,value)
testList = defaultlist(0) # need to provide a default value for auto-created items
testList[12]= 31
testList[23]= 1337
print(testList)
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1337]

Related

How can I tally the number of times each letter occurred in a string in a list

Word Problem:
Write and test a function that given a string of characters, returns a list with a tally (total number) of each individual character of the alphabet (A through Z) found in the string, ignoring case. The first element in the returned list is the tally for 'A'; the second element is the tally for 'B'; etc.
Function Definition
def countChars(s: str) -> list:
Example Input:
a = 'aBBcccDDDD'
print(countChars(a))
Example Output:
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
So far, I created a variable with all of the letters in a alphabet, and empty list for the result, a tally that will count the number occurrences and a variable that will keep track what letter I'm on. I decided to put it in a while loop to loop through every letter in the alphabet (A-Z) and for each letter, I made it so that it will loop through every character in that string. The problem is, my code can't run and I'm not sure if its going to work
def countChars(s: str) -> list:
tally = 0
result = []
alphabet = 1
letter = 'abcdefghijklmnopqrstuvwxyz'
while alphabet != 27:
for i in range(len(s)):
lower = s.lower()
if letter[i] in lower[i]:
tally +=1
result.append[tally]
else:
result.append[0]
alphabet +=1
return result
a = 'aBBcccDDDD'
print(countChars(a))
You could simplify your loop by utilizing ord():
def count_chars(s: str) -> list[int]:
counts = [0] * 26
for ch in s:
if ch.isalpha():
counts[ord(ch.lower()) - ord('a')] += 1
return counts
def main() -> None:
print(f'{count_chars("aBBcccDDDD") = }')
if __name__ == '__main__':
main()
Output:
count_chars("aBBcccDDDD") = [1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

How can I improve performance of Sudoku solver?

I can't improve the performance of the following Sudoku Solver code. I know there are 3 loops here and they probably cause slow performance but I can't find a better/more efficient way. "board" is mutated with every iteration of recursion - if there are no zeros left, I just need to exit the recursion.
I tried to isolate "board" from mutation but it hasn't changed the performance. I also tried to use list comprehension for the top 2 "for" loops (i.e. only loop through rows and columns with zeros), tried to find coordinates of all zeros, and then use a single loop to go through them - hasn't helped.
I think I'm doing something fundamentally wrong here with recursion - any advice or recommendation on how to make the solution faster?
def box(board,row,column):
start_col = column - (column % 3)
finish_col = start_col + 3
start_row = row - (row % 3)
finish_row = start_row + 3
return [y for x in board[start_row:finish_row] for y in x[start_col:finish_col]]
def possible_values(board,row,column):
values = {1,2,3,4,5,6,7,8,9}
col_values = [v[column] for v in board]
row_values = board[row]
box_values = box(board, row, column)
return (values - set(row_values + col_values + box_values))
def solve(board, i_row = 0, i_col = 0):
for rn in range(i_row,len(board)):
if rn != i_row: i_col = 0
for cn in range(i_col,len(board)):
if board[rn][cn] == 0:
options = possible_values(board, rn, cn)
for board[rn][cn] in options:
if solve(board, rn, cn):
return board
board[rn][cn] = 0
#if no options left for the cell, go to previous cell and try next option
return False
#if no zeros left on the board, problem is solved
return True
problem = [
[9, 0, 0, 0, 8, 0, 0, 0, 1],
[0, 0, 0, 4, 0, 6, 0, 0, 0],
[0, 0, 5, 0, 7, 0, 3, 0, 0],
[0, 6, 0, 0, 0, 0, 0, 4, 0],
[4, 0, 1, 0, 6, 0, 5, 0, 8],
[0, 9, 0, 0, 0, 0, 0, 2, 0],
[0, 0, 7, 0, 3, 0, 2, 0, 0],
[0, 0, 0, 7, 0, 5, 0, 0, 0],
[1, 0, 0, 0, 4, 0, 0, 0, 7]
]
solve(problem)
Three things you can do to speed this up:
Maintain additional state using arrays of integers to keep track of row, col, and box candidates (or equivalently values already used) so that finding possible values is just possible_values = row_candidates[row] & col_candidates[col] & box_candidates[box]. This is a constant factors thing that will change very little in your approach.
As kosciej16 suggested use the min-remaining-values heuristic for selecting which cell to fill next. This will turn your algorithm into crypto-DPLL, giving you early conflict detection (cells with 0 candiates), constraint propagation (cells with 1 candidate), and a lower effective branching factor for the rest.
Add logic to detect hidden singles (like the Norvig solver does). This will make your solver a little slower for the simplest puzzles, but it will make a huge difference for puzzles where hidden singles are important (like 17 clue puzzles).
A result that worked at the end thanks to 53x15 and kosciej16. Not ideal or most optimal but passes the required performance test:
def solve(board, i_row = 0, i_col = 0):
cells_to_solve = [((rn, cn), possible_values(board,rn,cn)) for rn in range(len(board)) for cn in range(len(board)) if board[rn][cn] == 0]
if not cells_to_solve: return True
min_n_of_values = min([len(x[1]) for x in cells_to_solve])
if min_n_of_values == 0: return False
best_cells_to_try = [((rn,cn),options) for ((rn,cn),options) in cells_to_solve if len(options) == min_n_of_values]
for ((rn,cn),options) in best_cells_to_try:
for board[rn][cn] in options:
if solve(board, rn, cn):
return board
board[rn][cn] = 0
return False

Dictionary filtering based on key does not works

I have the following dict:
ricavi={'Pergolato Recensione Completa': [0, 0, 0, 0, 0, 0, 200.0, 0, 150000.0, 0, 0, 0]}
I want to filter for key based on another variable, named prodotto that contains all key filtered.
prodotto=['Pergolato Recensione Completa']
How could get it?
I have tried the following code but does not work:
ricavi= dict((key,value) for key, value in ricavi.items() if key == prodotto)
Please try this (use key in prodotto):
ricavi={'Pergolato Recensione Completa': [0, 0, 0, 0, 0, 0, 200.0, 0, 150000.0, 0, 0, 0]}
prodotto=['Pergolato Recensione Completa']
ricavi2= dict((key,value) for key, value in ricavi.items() if key in prodotto)
print(ricavi2)
Alternatively if prodotto conaint always one element:
ricavi= dict((key,value) for key, value in ricavi.items() if key == prodotto[0])
Please note prodotto is a list so the first element is extracted to comparison.

Divide integer by a list to create a new list

I've created a list of number in a specified range. I now want to divide an value by each element in the list, and then add that new value to a new list.
Heres what I've got:
Y = []
value = 55 #can be any value of my choosing
newx = list(range(50,500,10))
newy = value/(newx)**2
Y.append(newy)
I keep getting TypeError with unsupported operand types for ** or pow(): list and int and I don't know why. NOTE: The ** is a syntax for power i.e 1/(x^2)
One "clean" option to do it is to use numpy array:
import numpy as np
value = 55 #can be any value of my choosing
Y = np.arange(50,500,10)
Y = value/(Y)**2
You got an error since in python you cannot take a square of a list (and you also cannot devide a number by a list). numpy array allows you to take a square and to do this division and many other mathematical operations.
Your description says what you want to do: divide a value by each element in a list. But that's not what you're actually doing, which is trying to divide the value by the list itself. You should do what you say you want to:
Y = [value/v for v in newx]
(I don't understand what the ** is for, you don't mention that anywhere.)
You can just use a list comprehension :
newy = [value/x**2 for x in newx]
The error you get is because the square of a list isn't defined.
The square of a numpy.array is defined though, and would be a new array with the square of each element from the original array.
Depending on the value and range you're working with, you might want to convert the int to float first. You could get 0s otherwise :
>>> value = 55
>>> newx = range(50, 500, 10)
>>> [value/x**2 for x in newx]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But :
>>> [value/float(x)**2 for x in newx]
[0.022, 0.015277777777777777, 0.011224489795918367, 0.00859375, 0.006790123456790123, 0.0055, 0.004545454545454545, 0.0038194444444444443, 0.003254437869822485, 0.0028061224489795917, 0.0024444444444444444, 0.0021484375, 0.0019031141868512112, 0.0016975308641975309, 0.0015235457063711912, 0.001375, 0.0012471655328798186, 0.0011363636363636363, 0.0010396975425330812, 0.0009548611111111111, 0.00088, 0.0008136094674556213, 0.0007544581618655693, 0.0007015306122448979, 0.0006539833531510107, 0.0006111111111111111, 0.0005723204994797086, 0.000537109375, 0.000505050505050505, 0.0004757785467128028, 0.0004489795918367347, 0.0004243827160493827, 0.00040175310445580715, 0.0003808864265927978, 0.0003616042077580539, 0.00034375, 0.0003271861986912552, 0.00031179138321995464, 0.00029745808545159546, 0.0002840909090909091, 0.00027160493827160494, 0.0002599243856332703, 0.00024898143956541424, 0.00023871527777777777, 0.00022907122032486465]

Fill missing values in lists

I have a list which consists of 0's and 1's. The list should ideally look like this 0,1,0,1,0,1,0,1,0,1,0,1,0,1.....
But due to some error in logging, my list looks like this: 0,1,0,1,1,1,0,1,0,0,0,1,0,1.... As one can clearly there are some missed 0's and 1's in middle. How can I fix this list to add those 0's and 1's in between the missing elements so as to get to the desired list values.
Here is the code used by me, this does the task for me but it is not the most pythonic way of writing scripts. So how can I improve on this script?
l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
indices = []
for i in range(1,len(l1)):
if l1[i]!=l1[i-1]:
continue
else:
if l1[i]==0:
val=1
else:
val=0
l1.insert(i, val)
EDIT
As asked in the comments, Let me explain why is this important rather than generating 1's and 0's. I have TTL pulse coming i.e. a series of HIGH(1) and LOW(0) coming in and simultaneously time for each of these TTL pulse is logged on 2 machines with different clocks.
Now while machine I is extremely stable and logging each sequence of HIGH(1) and low(1) accurately, the other machine ends up missing a couple of them and as a result I don't have time information for those.
All I wanted was to merge the missing TTL pulse on one machine wrt to the other machine. This will now allow me to align time on both of them or log None for not received pulse.
Reason for doing this rather than correcting the logging thing (as asked in comments) is that this is an old collected data. We have now fixed the logging issue.
You can try something like this:
from itertools import chain
l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
c = max(l1.count(0), l1.count(1))
print list(chain(*zip([0]*c,[1]*c)))
Output:
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
why would you have a list of 0,1,0,1,0,1? there is no good reason i can think of. oh well thats beyond the scope of this question i guess...
list(itertools.islice(itertools.cycle([0,1]),expected_length))
Just multiply a new list.
>>> l1 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1]
>>> l1
[0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1]
>>> [0,1] * (len(l1)//2)
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
If the list has an odd number of elements, add the necessary 0:
>>> l2 = [0,1,0,1,1,1,0,1,0,0,0,1,0,1,0]
>>> l2_ = [0,1] * (len(l1)//2)
>>> if len(l2)%2: l2_.append(0)
...
>>> l2
[0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0]
>>> l2_
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]

Categories

Resources