The global variable declared in the class in Python - python

I have this question for quit a while and would like to make sure that I understand it correctly. I am now working on a question on algorithm
Kth Largest Number in a Stream
Design a class to efficiently find the Kth largest element in a stream of numbers.
The class should have the following two things:
The constructor of the class should accept an integer array containing initial numbers from the stream and an integer K.
The class should expose a function add(int num) which will store the given number and return the Kth largest number.
The result is:
from heapq import *
class KthLargestNumberInStream:
# minHeap = []
def __init__(self, _input, _k):
self.k = _k
# the update minHeap will keep in the class and won't get cleared
self.minHeap = []
# rather than assigning values to input
# call the add function to add
for num in _input:
self.add(num)
def add(self, num):
# minHeap is defined outside this function and within the class
# need to use the self.minHeap to call it
heappush(self.minHeap, num)
# return the top k
if len(self.minHeap) > self.k:
heappop(self.minHeap)
# print(self.minHeap)
return self.minHeap[0]
def main():
kthLargestNumber = KthLargestNumberInStream([3, 1, 5, 12, 2, 11], 4)
print("4th largest number is: " + str(kthLargestNumber.add(6)))
print("4th largest number is: " + str(kthLargestNumber.add(13)))
print("4th largest number is: " + str(kthLargestNumber.add(4)))
main()
The print out the all the elements visited in the min heap is as:
[3]
[1, 3]
[1, 3, 5]
[1, 3, 5, 12]
[1, 2, 5, 12, 3]
[1, 2, 5, 12, 3, 11]
[1, 2, 5, 12, 3, 11, 6]
4th largest number is: 1
[1, 2, 5, 12, 3, 11, 6, 13]
4th largest number is: 1
[1, 2, 5, 4, 3, 11, 6, 13, 12]
4th largest number is: 1
I am curious that each time we called the kthLargestNumber = KthLargestNumberInStream([3, 1, 5, 12, 2, 11], 4), and why it won't create a new and empty heap and then add values to it, but keep the element from the previous call of the add function.
However, in this question Anther question, the max_sum will get reset each time.
Thanks for your help in advance.

Related

adding rows based on values of other rows

I have a list (in a dataframe) that looks like this:
oddnum = [1, 3, 5, 7, 9, 11, 23]
I want to create a new list that looks like this:
newlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23]
I want to test if the distance between two numbers is 2 (if oddnum[index+1]-oddnum[index] == 2)
If the distance is 2, then I want to add the number following oddnum[index] and create a new list (oddnum[index] + 1)
If the distance is greater than two, keep the list as is
I keep getting key error because (I think) the list runs out of [index] and [index+1] no longer exists once it reaches the end of the list. How do I do this?
To pass errors, the best method is to use try and except conditions. Here's my code:
oddnum = [1, 3, 5, 7, 9, 11, 23]
res = [] # The new list
for i in range(len(oddnum)):
res.append(oddnum[i]) # Append the first value by default
try: # Tries to run the code
if oddnum[i] + 2 == oddnum[i+1]: res.append(oddnum[i]+1) # Appends if the condition is met
except: pass # Passes on exception (in our case KeyError)
print(res)
oddnum = [1, 3, 5, 7, 9, 11, 23]
new_list = []
for pos, num in enumerate(oddnum):
new_list.append(num)
try:
if num-oddnum[pos+1] in [2, -2]:
new_list.append(num+1)
except:
pass
print(new_list)
Use try: except: to prevent exceptions popping up and ignore it

How find all pairs equal to N in a list

I have a problem with this algorithm- I have to find pairs in list:
[4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
which are equal to 12. The thing is that after making a pair those numbers (elements) can not be used again.
For now, I have code which you can find below. I have tried to delete numbers from the list after matching, but I feel that there is an issue with indexing after this.
It looks very easy but still not working. ;/
class Pairs():
def __init__(self, sum, n, arr ):
self.sum = sum
self.n = n
self.arr = arr
def find_pairs(self):
self.n = len(self.arr)
for i in range(0, self.n):
for j in range(i+1, self.n):
if (self.arr[i] + self.arr[j] == self.sum):
print("[", self.arr[i], ",", " ", self.arr[j], "]", sep = "")
self.arr.pop(i)
self.arr.pop(j-1)
self.n = len(self.arr)
i+=1
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
n = len(arr)
obj_Pairs = Pairs(sum, n, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()
update:
Thank you guys for the fast answers!
I've tried your solutions, and unfortunately, it is still not exactly what I'm looking for. I know that the expected output should look like this: [4, 8], [0, 12], [1, 11], [4, 8], [12, 0]. So in your first solution, there is still an issue with duplicated elements, and in the second one [4, 8] and [12, 0] are missing. Sorry for not giving output at the beginning.
With this problem you need to keep track of what numbers have already been tried. Python has a Counter class that will hold the count of each of the elements present in a given list.
The algorithm I would use is:
create counter of elements in list
iterate list
for each element, check if (target - element) exists in counter and count of that item > 0
decrement count of element and (target - element)
from collections import Counter
class Pairs():
def __init__(self, target, arr):
self.target = target
self.arr = arr
def find_pairs(self):
count_dict = Counter(self.arr)
result = []
for num in self.arr:
if count_dict[num] > 0:
difference = self.target - num
if difference in count_dict and count_dict[difference] > 0:
result.append([num, difference])
count_dict[num] -= 1
count_dict[difference] -= 1
return result
if __name__ == "__main__":
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
obj_Pairs = Pairs(12, arr)
result = obj_Pairs.find_pairs()
print(result)
Output:
[[4, 8], [8, 4], [0, 12], [12, 0], [1, 11]]
Demo
Brief
If you have learned about hashmaps and linked lists/deques, you can consider using auxiliary space to map values to their indices.
Pro:
It does make the time complexity linear.
Doesn't modify the input
Cons:
Uses extra space
Uses a different strategy from the original. If this is for a class and you haven't learned about the data structures applied then don't use this.
Code
from collections import deque # two-ended linked list
class Pairs():
def __init__(self, sum, n, arr ):
self.sum = sum
self.n = n
self.arr = arr
def find_pairs(self):
mp = {} # take advantage of a map of values to their indices
res = [] # resultant pair list
for idx, elm in enumerate(self.arr):
if mp.get(elm, None) is None:
mp[elm] = deque() # index list is actually a two-ended linked list
mp[elm].append(idx) # insert this element
comp_elm = self.sum - elm # value that matches
if mp.get(comp_elm, None) is not None and mp[comp_elm]: # there is no match
# match left->right
res.append((comp_elm, elm))
mp[comp_elm].popleft()
mp[elm].pop()
for pair in res: # Display
print("[", pair[0], ",", " ", pair[1], "]", sep = "")
# in case you want to do further processing
return res
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
n = len(arr)
obj_Pairs = Pairs(sum, n, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()
Output
$ python source.py
[4, 8]
[0, 12]
[4, 8]
[1, 11]
[12, 0]
To fix your code - few remarks:
If you iterate over array in for loop you shouldn't be changing it - use while loop if you want to modify the underlying list (you can rewrite this solution to use while loop)
Because you're iterating only once the elements in the outer loop - you only need to ensure you "popped" elements in the inner loop.
So the code:
class Pairs():
def __init__(self, sum, arr ):
self.sum = sum
self.arr = arr
self.n = len(arr)
def find_pairs(self):
j_pop = []
for i in range(0, self.n):
for j in range(i+1, self.n):
if (self.arr[i] + self.arr[j] == self.sum) and (j not in j_pop):
print("[", self.arr[i], ",", " ", self.arr[j], "]", sep = "")
j_pop.append(j)
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
obj_Pairs = Pairs(sum, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()

How to print smallest number from list when mode is not available?

I Would like to find Mode in python array or list, but if all numbers appears at only once(or we can say there is no Mode) I wanted to print smallest number.
n_num = [64630, 11735, 14216, 99233, 14470, 4978, 73429, 38120, 51135, 67060]
from statistics import mode
def mode(n_num):
n_num.sort()
m = min(n_num)
return m
print(str(mode(n_num)))
You can use multimode() from the statistics package instead of mode(). This will return multiple values when there is more than one mode to choose from. You can take the min() from that:
from statistics import multimode
n_num = [10, 9, 1, 2, 3, 4]
min(multimode(n_num))
# 1
n_num = [10, 9, 1, 2, 3, 4, 9, 10 ]
min(multimode(n_num))
#9
[Note: this requires python 3.8]
try to use the try statement
import statistics
def special_mode(iterable):
try:
result = statistics.mode(iterable)
except statistics.StatisticsError: # if mode() fail, it do min()
result = min(iterable)
return result
mylist = [0, 1, 6, 9, 1, -7]
print(special_mode(mylist))
# return the 1 because of the mode function
mylist = [0, 1, 6, 9, -7]
print(special_mode(mylist))
# return the -7 beacuse it's the smallest
hope it was helpful
Python already has a min and max function built-in to find the smallest and largest values in a list
n = [64630, 11735, 14216, 99233, 14470, 4978, 73429, 38120, 51135, 67060]
smallest_number = min(n)
largest_number = max(n)

If/else statement with a triplet that sum to a given value

I'm writing a sum up game where two players will take turns picking a random number in the range (1,9), no repeated number allowed. So I'm struggling at
If at any point exactly three of the player's numbers sum to 15, then that player has won.
If the first player picks [7, 2, 3, 5], he will win because 7+3+5 = 15
So my question is why doesn't the program stop when first_player has inputs == 15
I want to avoid importing any libs.
Instead of generating all permutations at each step, maintain a map of what each permutation sums to, then add two branches to each branch at each move.
Think of each entry as a set of bits, ie with each permutation you either include a given entry or not, eg if the numbers are [7, 3, 2] you might store [1, 0, 1] for the combination of the 7 and the 2.
You can make a hashmap of 101->9 etc and when someone adds a 3 to it you add an entry for 1010->9 and 1011->12. As soon as you see the target you know the game is over.
So the evolution of [7, 3, 2] would be
0->0
1->7
00->0
01->3
10->7
11->10
000->0
001->2
010->3
011->5
100->7
101->9
110->10
111->12
A more efficient way would be to find only those numbers whose sum is equal to the target that is 15.
entry = [7, 5, 1, 3]
def is_sum_15(nums):
res = []
search_numbers(nums, 3, 15, 0, [], res)
return len(res) != 0
def search_numbers(nums, k, n, index, path, res):
if k < 0 or n < 0:
return
if k == 0 and n == 0:
res.append(path)
for i in range(index, len(nums)):
search_numbers(nums, k-1, n-nums[i], i+1, path+[nums[i]], res)
print(is_sum_15(entry)) # True
An inefficient but easy way is to use itertools.permutations:
>>> entry = [7, 2, 3, 5]
>>> import itertools
>>> [sum(triplet) for triplet in itertools.permutations(entry, r=3) if sum(tr]
[12, 14, 12, 15, 14, 15, 12, 14, 12, 10, 14, 10, 12, 15, 12, 10, 15, 10, 14, 15, 14, 10, 15, 10]
>>> any(sum(triplet) == 15 for triplet in itertools.permutations(entry, r=3))
True
It's inefficient, because you would be trying all permutations every time entry gets expanded with a new number.

Custom list traversal and modification

I'm traversing a two-dimensional list (my representation of a matrix) in an unusual order: counterclockwise around the outside starting with the top-left element.
I need to do this more than once, but each time I do it, I'd like to do something different with the values I encounter. The first time, I want to note down the values so that I can modify them. (I can't modify them in place.) The second time, I want to traverse the outside of the matrix and modify the values of the matrix as I go, perhaps getting my new values from some generator.
Is there a way I can abstract this traversal to a function and still achieve my goals? I was thinking that this traverse-edge function could take a function and a matrix and apply the function to each element on the edge of the matrix. However, the problems with this are two-fold. If I do this, I don't think I can modify the matrix that's given as an argument, and I can't yield the values one by one because yield isn't a function.
Edit: I want to rotate a matrix counterclockwise (not 90 degrees) where one rotation moves, for example, the top-left element down one spot. To accomplish this, I'm rotating one "level" (or shell) of the matrix at a time. So if I'm rotating the outermost level, I want to traverse it once to build a list which I can shift to the left, then I want to traverse the outermost level again to assign it those new values which I calculated.
Just create 4 loops, one for each side of the array, that counts through the values of the index that changes for that side. For example, the first side, whose x index is always 0, could vary the y from 0 to n-2 (from the top-left corner to just shy of the bottom-left); repeat for the other sides.
I think there are two approaches you can take to solving your problem.
The first option is to create a function that returns an iterable of indexes into the matrix. Then you'd write your various passes over the matrix with for loops:
for i, j in matrix_border_index_gen(len(matrix), len(matrix[0])): # pass in dimensions
# do something with matrix[i][j]
The other option is to write a function that works more like map that applies a given function to each appropriate value of the matrix in turn. If you sometimes need to replace the current values with new ones, I'd suggest doing that all the time (the times when you don't want to replace the value, you can just have your function return the previous value):
def func(value):
# do stuff with value from matrix
return new_value # new_value can be the same value, if you don't want to change it
matrix_border_map(func, matrix) # replace each value on border of matrix with func(value)
I have added a few lines of python 3 code here. It has the mirror function and a spiral iterator (not sure, if that's what you meant). No doc strings (sorry). It is readable though. Change print statement for python 2.
EDIT : FIXED A BUG
class Matrix():
def __init__(self, rows=5, cols=5):
self.cells = [[None for c in range(cols)] for r in range(rows)]
def transpose(self):
self.cells = list(map(list, zip(*self.cells)))
def mirror(self):
for row in self.cells:
row.reverse()
def invert(self):
self.cells.reverse()
def rotate(self, clockwise=True):
self.transpose()
self.mirror() if clockwise else self.invert()
def iter_spiral(self, grid=None):
grid = grid or self.cells
next_grid = []
for cell in reversed(grid[0]):
yield cell
for row in grid[1:-1]:
yield row[0]
next_grid.append(row[1:-1])
if len(grid) > 1:
for cell in grid[-1]:
yield cell
for row in reversed(grid[1:-1]):
yield row[-1]
if next_grid:
for cell in self.iter_spiral(grid=next_grid):
yield cell
def show(self):
for row in self.cells:
print(row)
def test_matrix():
m = Matrix()
m.cells = [[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]]
print("We expect the spiral to be:", "4, 3, 2, 1, 5, 9, 13, 14, 15, 16, 12, 8, 7, 6, 10, 11", sep='\n')
print("What the iterator yields:")
for cell in m.iter_spiral():
print(cell, end=', ')
print("\nThe matrix looks like this:")
m.show()
print("Now this is how it looks rotated 90 deg clockwise")
m.rotate()
m.show()
print("Now we'll rotate it back")
m.rotate(clockwise=False)
m.show()
print("Now we'll transpose it")
m.transpose()
m.show()
print("Inverting the above")
m.invert()
m.show()
print("Mirroring the above")
m.mirror()
m.show()
if __name__ == '__main__':
test_matrix()
This is the output:
We expect the spiral to be:
4, 3, 2, 1, 5, 9, 13, 14, 15, 16, 12, 8, 7, 6, 10, 11
What the iterator yields:
4, 3, 2, 1, 5, 9, 13, 14, 15, 16, 12, 8, 7, 6, 10, 11,
The matrix looks like this:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14, 15, 16]
Now this is how it looks rotated 90 deg clockwise
[13, 9, 5, 1]
[14, 10, 6, 2]
[15, 11, 7, 3]
[16, 12, 8, 4]
Now we'll rotate it back
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14, 15, 16]
Now we'll transpose it
[1, 5, 9, 13]
[2, 6, 10, 14]
[3, 7, 11, 15]
[4, 8, 12, 16]
Inverting the above
[4, 8, 12, 16]
[3, 7, 11, 15]
[2, 6, 10, 14]
[1, 5, 9, 13]
Mirroring the above
[16, 12, 8, 4]
[15, 11, 7, 3]
[14, 10, 6, 2]
[13, 9, 5, 1]
I would go with generator functions. They can be used to create iterators over which we can iterate. An Example of a generator function -
def genfunc():
i = 0
while i < 10:
yield i
i = i + 1
>>> for x in genfunc():
... print(x)
...
0
1
2
3
4
5
6
7
8
9
When calling the generator function, it returns a generator object -
>>> genfunc()
<generator object genfunc at 0x00553AD0>
It does not start going over the function at that point. When you start iterating over the generator object, calling for its first element, it starts going over the function, untill it reaches the first yield statement, and at that point it returns the value (in above case, it returns value of i) . And it also saves the state of the function at that point (that is it saves at what point the execution was when the value was yielded, what were the values for the variables in the local namespace, etc).
Then when it tries to get the next value, again execution starts from where it stopped last time, till it again yield another value. And this continues on.

Categories

Resources