How to handle errors in hash tables in python 3? - arrays

Getting a basic error in Hash tables
n = int(input("Enter the length of the array "))
a = [0 for i in range(n)]
for i in range(0,n):
a[i] = int(input("Enter elements of array: "))
# maxi = max(a)
# print(maxi)
has = [[0 for i in range(n)]
for j in range(2)]
for i in range(0,n):
if(a[i]>=0):
has[a[i]][0] = 1
else:
has[abs(a[i])][1] = 1
search = int(input("Enter the element to be searched: "))
# if(search>0):
def search1(search):
if(search>0):
if(a[search][0] == 1):
print("Present")
else:
print("Absent")
else:
search = abs(search)
if(a[search][1] == 1):
print("Present")
else:
print("absent")
Can anyone please help me out if why is this happening?
Error: list index out of range
This code first takes an array of input from the user and the numbers are then stored in a hash table based on positive or negative numbers. Then the search algorithm is made based on index itself to give the time complexity of O(1). But in between, I am getting a list index out of range error. Please help to solve the following error.

So, you are simulating a hash using a list, right? Here is the problem: The expression
[[0 for i in range(n)]
for j in range(2)]
generates a list of lists. If your print it, you'll see that is has two items (two lists), so an indexing operation like a[i] with i > 1 won't work. Maybe you wanted to generate a list with a different structure?
[[0 for i in range(2)]
for j in range(n)]
Or you can change the indexing logic, e.g. has[1][abs(a[i])] = 1.
In general, it helps to print the state of the variables in between to stay informed about what's going on.

Related

Finding max sum with operation limit

As an input i'm given an array of integers (all positive).
Also as an input i`m given a number of "actions". The goal is to find max possible sum of array elements with given number of actions.
As an "action" i can either:
Add current element to sum
Move to the next element
We are starting at 0 position in array. Each element could be added only once.
Limitation are:
2 < array.Length < 20
0 < number of "actions" < 20
It seems to me that this limitations essentially not important. Its possible to find each combination of "actions", but in this case complexity would be like 2^"actions" and this is bad...))
Examples:
array = [1, 4, 2], 3 actions. Output should be 5. In this case we added zero element, moved to first element, added first element.
array = [7, 8, 9], 2 actions. Output should be 8. In this case we moved to the first element, then added first element.
Could anyone please explain me the algorithm to solve this problem? Or at least the direction in which i shoudl try to solve it.
Thanks in advance
Here is another DP solution using memoization. The idea is to represent the state by a pair of integers (current_index, actions_left) and map it to the maximum sum when starting from the current_index, assuming actions_left is the upper bound on actions we are allowed to take:
from functools import lru_cache
def best_sum(arr, num_actions):
'get best sum from arr given a budget of actions limited to num_actions'
#lru_cache(None)
def dp(idx, num_actions_):
'return best sum starting at idx (inclusive)'
'with number of actions = num_actions_ available'
# return zero if out of list elements or actions
if idx >= len(arr) or num_actions_ <= 0:
return 0
# otherwise, decide if we should include current element or not
return max(
# if we include element at idx
# we spend two actions: one to include the element and one to move
# to the next element
dp(idx + 1, num_actions_ - 2) + arr[idx],
# if we do not include element at idx
# we spend one action to move to the next element
dp(idx + 1, num_actions_ - 1)
)
return dp(0, num_actions)
I am using Python 3.7.12.
array = [1, 1, 1, 1, 100]
actions = 5
In example like above, you just have to keep moving right and finally pickup the 100. At the beginning of the array we never know what values we are going to see further. So, this can't be greedy.
You have two actions and you have to try out both because you don't know which to apply when.
Below is a python code. If not familiar treat as pseudocode or feel free to convert to language of your choice. We recursively try both actions until we run out of actions or we reach the end of the input array.
def getMaxSum(current_index, actions_left, current_sum):
nonlocal max_sum
if actions_left == 0 or current_index == len(array):
max_sum = max(max_sum, current_sum)
return
if actions_left == 1:
#Add current element to sum
getMaxSum(current_index, actions_left - 1, current_sum + array[current_index])
else:
#Add current element to sum and Move to the next element
getMaxSum(current_index + 1, actions_left - 2, current_sum + array[current_index])
#Move to the next element
getMaxSum(current_index + 1, actions_left - 1, current_sum)
array = [7, 8, 9]
actions = 2
max_sum = 0
getMaxSum(0, actions, 0)
print(max_sum)
You will realize that there can be overlapping sub-problems here and we can avoid those repetitive computations by memoizing/caching the results to the sub-problems. I leave that task to you as an exercise. Basically, this is Dynamic Programming problem.
Hope it helped. Post in comments if any doubts.

"ValueError: too many values to unpack (expected 2)" should not happen here

I'm currently trying to create a Sudoku without help but i'm stuck on one issue.
def play():
global myinput
global column_rdm
sudoku_col = [[] for _ in range(9)]
for i in range(9):
sudoku_col[i].append(0)
h = 1
try:
while h < 10:
rdm_list = random.sample(range(1, 10), 9)
test_var = 0
for j in range(9):
if rdm_list[j] not in sudoku_col[j]:
test_var += 1
if test_var == 9:
for rdm_number, g in rdm_list, range(9):
sudoku_col[g].append(rdm_number)
# Input the values found in the sudoku
column_rdm = f"{rdm_number}"
myinput = Input(h, g+1)
myinput.value_def(column_rdm) # end
h += 1
update()
# except Exception as e:
# print("Erreur dans la création du Sudoku")
finally:
print(h)
Here the function that should create my Sudoku. I create random lists of 9 numbers which will be my sudoku raws, and i check if each item of those lists is already present in its column with my "sudoku_col". If the test is OK (that is, test_var == 9), then I add this raw to my template. If not, I create a new random list and let it complete the test again. I do that until I have 9 raws (h < 10).
However, the code stops at line "for rdm_number, g in rdm_list, range(9):" due to a ValueError. That should not happen, because rdm_list and range(9) have the same lenght and each item in both lists should be iterated correctly. What am I missing here ?
Thank you for your time
It should be
for rdm_number, g in zip(rdm_list, range(9)):
what you are doing is the same as
for rdm_number, g in (rdm_list, range(9)):
which creates a tuple with two items that you iterate over, you can see that happen if you do this (it will print out whatever is the rdm_list and range(0, 9)):
for sth in rdm_list, range(9):
print(sth)
also while h < 10 can just be replaced with for h in range(9): and you don't need to increase any variables and for loops are faster.
Another improvement would be to do this (instead of using the range and accessing values by index):
for rdm, s_col in zip(rdm_list, sudoku_col):
if rdm not in s_col:
test_var += 1
Also this:
sudoku_col = [[] for _ in range(9)]
for i in range(9):
sudoku_col[i].append(0)
can easily be reduced to
sudoku_col = [[0] for _ in range(9)]
Again you shouldn't use range to access values by using index, you should iterate over the values like this: for value in iterable:, instead of for index in range(len(iterable)), if you also need the index then use this: for index, value in enumerate(iterable):

LeetCode Find All Numbers Disappeared in an Array Question

The problem I am doing is stated as follows:
Given an array nums of n integers where nums[i] is in the range [1, n], return an array of all the integers in the range [1, n] that do not appear in nums.
I found a solution that takes O(n) space fairly quickly however this problem has a condition to find a constant space solution and I do not understand the solution that is given. The constant space solution is recreated here as follows:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
# Iterate over each of the elements in the original array
for i in range(len(nums)):
# Treat the value as the new index
new_index = abs(nums[i]) - 1
# Check the magnitude of value at this new index
# If the magnitude is positive, make it negative
# thus indicating that the number nums[i] has
# appeared or has been visited.
if nums[new_index] > 0:
nums[new_index] *= -1
# Response array that would contain the missing numbers
result = []
# Iterate over the numbers from 1 to N and add all those
# that have positive magnitude in the array
for i in range(1, len(nums) + 1):
if nums[i - 1] > 0:
result.append(i)
return result
I don't understand how this code works. To me it seems that every element will be made negative in the first pass and therefore no values will be appended to the answer list. I ran it through a debugger and it seems that is not what is happening. I was hoping that someone can explain to me what it is doing.
Let's take an example:
nums = [4,3,2,7,8,2,3,1]
Now Let's iterate over it,
Index-1: Value = 4 -> Mark (Value - 1) -> (4-1) index element as negative provided that element is positive.
Now, nums = [4,3,2,-7,8,2,3,1]
In this do for every index,
You will come to this:
nums = [-4,-3,-2,-7,8,2,-3,-1]
The element at index = 4 and index = 5 are positive.
So, the answer is [4+1,5+1] = [5,6].
Hope you understood this🔑.

Ruby - Efficient method of checking if sum of two numbers in array equal a value

Here's my problem: I have a list of 28,123 numbers I need to iterate through and an array of 6965 other numbers checking if the sum of two numbers (can be the same number) have equal value to each of the 28,123 numbers. I want to put them in a new array or mark them as true / false. Any solutions I've come up with so far are extremely inefficient.
So a dumbed-down version of what I want is if I have the following: array = [1, 2, 5] and the numbers 1 to 5 would return result = [2, 3, 4] or the array of result = [false, true, true, true, false]
I read this SE question: Check if the sum of two different numbers in an array equal a variable number? but I need something more efficient in my case it seems, or maybe a different approach to the problem. It also doesn't seem to work for two of the same number being added together.
Any help is much appreciated!
non_abundant(n) is a function that returns the first n non_abundant numbers. It executes almost instantaneously.
My Code:
def contains_pair?(array, n)
!!array.combination(2).detect { |a, b| a + b == n }
end
result = []
array = non_abundant(6965)
(1..28123).each do |n|
if array.index(n) == nil
index = array.length - 1
else
index = array.index(n)
end
puts n
if contains_pair?( array.take(index), n)
result << n
end
end
numbers = [1, 2, 5]
results = (1..10).to_a
numbers_set = numbers.each_with_object({}){ |i, h| h[i] = true }
results.select do |item|
numbers.detect do |num|
numbers_set[item - num]
end
end
#=> [2, 3, 4, 6, 7, 10]
You can add some optimizations by sorting your numbers and checking if num is bigger then item/2.
The complexity is O(n*m) where n and m are lengths of two lists.
Another optimization is if numbers list length is less then results list (n << m) you can achieve O(n*n) complexity by calculating all possible sums in numbers list first.
The most inefficient part of your algorithm is the fact that you are re-calculating many possible sums of combinations, 28123 times. You only need to do this once.
Here is a very simple improvement to your code:
array = non_abundant(6965)
combination_sums = array.combination(2).map {|comb| comb.inject(:+)}.uniq
result = (1..28123).select do |n|
combination_sums.include? n
end
The rest of your algorithm seems to be an attempt to compensate for that original performance mistake of re-calculating the sums - which is no longer needed.
There are further optimisations you could potentially make, such as using a binary search. But I'm guessing this improvement will already be sufficient for your needs.

How to do C++ style(indexed) nested loops in python?

What is the equivalent of the following in python?
for (i=0; i<n; i++)
for (j=i+1; j<n; j++)
//do stuff with A[i], A[j]
Or in some sense, the following. It should also remove the element from A at the completion of each round of the loop.
for a in A:
for a' in A/{a}: #i.e. rest of the elements of A
#do something with a,a'
#remove a from A
Is there a pythonic way of doing this without using enumerate()?
Edits:
Sorry for the bad description.
In the first example, I mean to use i & j only as indices. Their values do not matter. Its just a rough c++ equivalent of the latter.
The outer loop is executed n times. The inner loop is executed (n-1), (n-2)...0 times for each iteration of the outer loop.
Maybe this might help (pseudocode):
function next_iteration(list):
head = first element
tail = remaining elements #list
each element in tail interacts with head one by one
next_iteration(tail)
PS: All code samples above are pseudocodes. I'm trying to express something that is still a bit vague in my mind.
I intepret what you're asking as
How can I iterate over all pairs of distinct elements of a container?
Answer:
>>> x = {1,2,3}
>>> import itertools
>>> for a, b in itertools.permutations(x, 2):
... print a, b
...
1 2
1 3
2 1
2 3
3 1
3 2
EDIT: If you don't want both (a,b) and (b,a), just use itertools.combinations instead.
Since your two questions are different, here is solution for your second problem:
for i in xrange(len(A)):
for j in xrange(len(A)):
if i != j:
do_stuff(A[i], A[j])
or using itertools (I think using the included batteries is very pythonic!):
import itertools
for a, b in itertools.permutations(A, 2):
do_stuff(a, b)
This applies do_stuff to all combinations of 2 different elements from A. I you want to store the result just use:
[do_stuff(a, b) for a, b in itertools.permutations(A, 2)]
How about:
for i in range(0,n):
for j in range (i+1,n):
# do stuff
for i in range(0,n):
for j in range(i+1,n):
# do stuff
Still can't leave comments.. but basically what the other two posts said - but get in the habit of using xrange instead of range.
for i in xrange(0,n):
for j in xrange(i+1,n):
# do stuff
You could make the inner loop directly over a slice. Not saying this is any better, but it is another approach.
for i in range(0,len(x)):
a = x[i]
for b in x[i+1:]:
print a, b
Another way to approach this is - if n is an sequence that provides the iterable interface, then in Python you can simplify your code by iterating over the object directly:
for i in n:
for some_var in n[n.index(i):]: # rest of items
# do something
I hope I understood your loop correctly, because as others have stated - they don't do the same thing.
For the first one of your questions, as already mentioned in other answers:
for i in xrange(n):
for j in xrange(i+1, n):
# do stuff with A[i] and A[j]
For the second one:
for i, a in enumerate(A):
for b in A[i+1:]:
# do stuff with a and b
Your psuedocode almost has it:
function next_iteration(list):
head = first element
tail = remaining elements #list
each element in tail interacts with head one by one
next_iteration(tail)
Python code:
def next_iteration(lst):
head, tail = lst[0], lst[1:]
for item in tail:
print(head, item)
if tail:
next_iteration(tail)
Which, when tried with next_iteration([1, 2, 3]), prints:
1 2
1 3
2 3
You can use xrange to generate values for i and j respectively as show below:
for i in xrange(0, n):
for j in xrange(i + 1, n):
# do stuff
In the first for-loop, enumerate() walks through the array and makes the index,value of each element available to the second for-loop. In the second loop, range() makes j = i+1 --> len(a) available. At this point you'd have exactly what you need which is i & j to do your operation.
>>> a = [1,2,3,4]
>>> array_len = len(a)
>>> for i,v in enumerate(a):
... for j in range(i+1, array_len):
... print a[i], a[j]
...
1 2
1 3
1 4
2 3
2 4
3 4
>>>

Resources