how to loop through a dictionary as a range - python-3.x

I have a dictionary with key a start time o a video and its value as end time. each key value pair represents different group. how to check a number exists in range.
eg:
dictvid = {146: 209, 509: 539, 0: 145, 304: 320}
from 0 to 539 - 210 to 303 and 321 to 508 needs to be in another dictionary
i.e
newgroup = {210:303,321:508}

You can construct a range object from each key-value pair which will give you an O(n) solution (O(n) for iterating over the dictionary + O(1) for the in check inside each range object). Note the + 1 since range objects are exclusive in the end).
print(any(208 in range(start, end + 1) for start, end in dictvid.items()))
print(any(211 in range(start, end + 1) for start, end in dictvid.items()))
Outputs
True
False

from itertools import chain, groupby
dictvid = {146: 209, 509: 539, 0: 145, 304: 320}
i_from = 0
i_to = 539
out = dict()
s = sorted(set(range(i_from, i_to+1)).difference(chain.from_iterable(range(k, v+1) for k, v in dictvid.items())))
for _, g in groupby(enumerate(s), lambda v: v[0]-v[1]):
l = [*g]
out[l[0][1]] = l[-1][1]
print(out)
Prints:
{210: 303, 321: 508}

Related

How to track down the mistake in this merge function?

I can't figure out what the problem with this merge sort implementation is. I've confirmed the problem is in the merge function rather than merge_sort by replacing merge with the same function from some examples found online and it works fine, however I can't find the mistake in my implementation.
Expected result: list sorted in order from smallest to largest.
Actual result: left side of list modified (not in order) and right side unmodified.
I've tried adding print statements at various points in the program and it looks like the problem is related to rightList not being created properly but I can't figure out why.
What can I do to track down the cause of this?
Code:
def merge_sort(toSort, left, right):
# check if we have more than one remaining element
if left >= right:
return
# get middle of array, note the result needs to be an int
mid = (left + right) // 2
# call merge sort on the left and right sides of the list
merge_sort(toSort, left, mid)
merge_sort(toSort, mid+1, right)
# merge the results
merge(toSort, left, right, mid)
# merge function taking a list along with the positions
# of the start, middle and end
def merge(toSort, left, right, mid):
# split the list into two separate lists based on the mid position
leftList = toSort[left:mid+1]
rightList = toSort[mid+1:right+1]
# variables to track position in left and right lists and the sorted list
lIndex = 0
rIndex = 0
sIndex = lIndex
# while there are remaining elements in both lists
while lIndex < len(leftList) and rIndex < len(rightList):
#if the left value is less than or equal to the right value add it to position sIndex in toSort
# and move lIndex to next position
if leftList[lIndex] <= rightList[rIndex]:
toSort[sIndex] = leftList[lIndex]
lIndex = lIndex + 1
# otherwise set sIndex to right value and move rIndex to next position
else:
toSort[sIndex] = rightList[rIndex]
rIndex = rIndex + 1
sIndex = sIndex + 1
# add the remaining elements from either leftList or rightList
while lIndex < len(leftList):
toSort[sIndex] = leftList[lIndex]
lIndex = lIndex + 1
sIndex = sIndex + 1
while rIndex < len(rightList):
toSort[sIndex] = rightList[rIndex]
rIndex = rIndex + 1
sIndex = sIndex + 1
unsorted = [33, 42, 9, 37, 8, 47, 5, 29, 49, 31, 4, 48, 16, 22, 26]
print(unsorted)
merge_sort(unsorted, 0, len(unsorted) - 1)
print(unsorted)
Output:
[33, 42, 9, 37, 8, 47, 5, 29, 49, 31, 4, 48, 16, 22, 26]
[16, 22, 26, 49, 31, 4, 48, 29, 49, 31, 4, 48, 16, 22, 26]
Edit
Link to example of code in colab: https://colab.research.google.com/drive/1z5ouu_aD1QM0unthkW_ZGkDlrnPNElxm?usp=sharing
The index variable into toSort, sIndex should be initialized to left instead of 0.
Also note that it would be more readable and consistent to pass right as 1 + the index of the last element of the slice, which is consistent with the slice notation in python and would remove the +1/-1 adjustments here and there. The convention where right is included is taught in java classes, but it is error prone and does not allow for empty slices.
Using simpler index variable names would help readability, especially with more indent space.
Here is a modified version:
# sort the elements in toSort[left:right]
def merge_sort(toSort, left, right):
# check if we have more than one remaining element
if right - left < 2:
return
# get middle of array, note: the result needs to be an int
mid = (left + right) // 2
# call merge sort on the left and right sides of the list
merge_sort(toSort, left, mid)
merge_sort(toSort, mid, right)
# merge the results
merge(toSort, left, mid, right)
# merge function taking a list along with the positions
# of the start, middle and end, in this order.
def merge(toSort, left, mid, right):
# split the list into two separate lists based on the mid position
leftList = toSort[left : mid]
rightList = toSort[mid : right]
# variables to track position in left and right lists and the sorted list
i = 0
j = 0
k = left
# while there are remaining elements in both lists
while i < len(leftList) and j < len(rightList):
# if the left value is less than or equal to the right value add it to position k in toSort
# and move i to next position
if leftList[i] <= rightList[j]:
toSort[k] = leftList[i]
i += 1
# otherwise set it to right value and move j to next position
else:
toSort[k] = rightList[j]
j += 1
k += 1
# add the remaining elements from either leftList or rightList
while i < len(leftList):
toSort[k] = leftList[i]
i += 1
k += 1
while j < len(rightList):
toSort[k] = rightList[j]
j += 1
k += 1
unsorted = [33, 42, 9, 37, 8, 47, 5, 29, 49, 31, 4, 48, 16, 22, 26]
print(unsorted)
merge_sort(unsorted, 0, len(unsorted))
print(unsorted)

Start counting indexes from 1 instead of 0 of a list

I created a program to get the the max value of a list and the position of its occurrences (list starting at indexing with 1 not 0) but I can't manage to find any useful solutions.
The input is always a string of numbers divided by zero.
This is my code:
inp = list(map(int,input().split()))
m = max(inp)
count = inp.count(m)
print(m)
def maxelements(seq): # #SilentGhost
return [i for i, j in enumerate(seq) if j == m]
print(maxelements(inp))
I expect to output the maximum value and then all the positions of its occurrences. (also is it possible to do without brackets as in the example below?)
Input: 4 56 43 45 2 56 8
Output: 56
2 6
If you want to shift index values, you could just do
return [i + 1 for i, j in enumerate(seq) if j == m]
more generally any transformation of i or j!
def f(i, j):
# do whatever you want, and return something
return i + 1
return [f(i, j) for i, j in enumerate(seq) if j == m]
Without brackets, as a string:
return " ".join(str(i + 1) for i, j in enumerate(seq) if j==m)
Specifiy start=1 with enumerate():
>>> l = [4, 56, 43, 45, 2, 56, 8]
>>> max_num = max(l)
>>> [i for i, e in enumerate(l, start=1) if e == max_num]
[2, 6]
By default enumerate() uses start=0, because indices start at 0.

How to determine the maximum,minimum and average values of the matrix

I need to create a matrix, where the user can input his values and determine the maximum value of the matrix, the minimum value and the average value of all matrix's data
I created the matrix, where I can input my own values and I tried to write which could determine the maximum and minimum value. However, after several checks, I understood, that my piece of code, which determines max and min values, doesn't work.
line = int(input('Enter the amount of lines:'))
columns = int(input('Enter the amount of columns:'))
matrix = []
for i in range(0, columns):
matrix.append([])
for i in range(0, line):
for j in range(0, columns):
matrix[i].append(j)
matrix[i][j] = 0
for i in range(0, line):
for j in range(0,columns):
matrix[i][j] = int(input('Enter the value:'))
avg = matrix
for i in range(0, line):
for j in range(0, columns):
max_val = matrix[j]
min_val = matrix[j]
for j in range(0, len(matrix[j]), 1):
max_val = max(max_val, matrix[j])
min_val = min(min_val, matrix[j])
maxVal = max_val[0]
minVal = min_val[0]
for i in range(0, len(max_val), 1):
maxVal = max(maxVal, max_val[i])
minVal = min(minVal, min_val[i])
print(matrix)
print('The maximum value is ' + str(maxVal))
print('The minimum value is ' + str(minVal))
I excepted the result, which will print me the matrix, maximum value, minimum value and average value
One way of doing it with Python lists is this:
(I'll just do find_min(), as find_max() and compute_mean() would be pretty much the same.)
import random
def gen_random_matrix(rows, cols, min_val=1, max_val=100):
return [
[random.randint(min_val, max_val) for j in range(cols)]
for i in range(rows)]
def find_min(matrix):
rows = len(matrix)
cols = len(matrix[0])
min_i, min_j = 0, 0
min_val = matrix[min_i][min_j]
for i in range(rows):
for j in range(cols):
if matrix[i][j] < min_val:
min_i = i
min_j = j
min_val = matrix[i][j]
return min_val, min_i, min_j
random.seed(0)
matrix = gen_random_matrix(3, 4)
print(matrix)
# [[50, 98, 54, 6], [34, 66, 63, 52], [39, 62, 46, 75]]
print(find_min(matrix))
# (6, 0, 3)

Dp with memoize

This is a problem in 'introduction to algorithm' dp chapter
We have to cut a long steel in order to gain most benefits
the first line is length and the second line is price.
def cut_rod_mem(n, p):
m = [0]
for i in range(10):
m.append(-1)
def inner(n, p):
if m[n]!=-1:
return m[n]
for i in range(1, n + 1):
t = p[i] + inner(n - i, p)
if t > m[n]:
m[n] = t
return m[n]
return inner(n,p)
I am confused if this list will be out of range?
It will not be out of range because the elements of array are indexed from 0 to n-1, i.e in the above case 0 to 9. In the function inner the for loop goes from 1 to n, thus inner(n - i, p) is in range with values inner(9, p) ..... inner(0, p).

Getting Rid of Needless Arguments

import random
def makeTable(f, v):
f = random.randint(1, 7)
v = random.randint(f, 10)
table = [[0 for x in range(v)] for y in range(f)]
for i in range(f):
for j in range(v):
table[i][j] = random.randint(1, 100)
return table
def printTable(table):
# print the table (helpful for visualizing)
for i in range(len(table)):
print("\t".join(str(a) for a in table[i]))
def calculateSums(startRow, startColumn, initialSum):
if startRow == f - 1:
# if the last row is reached add each of the coming values
# to the variable initialSum and append to the list totalSums.
for k in range(startColumn, v):
totalSums.append(initialSum + table[f - 1][k])
else:
while startColumn <= (v - f + startRow):
# the constraint (v-f+startRow) determines the limit
# how far each row can go to the right.
# e.g. in a 3*5 table the limit for the first row is the third column,
# the limit for the 2nd row is the fourth column, etc.
initialSum += table[startRow][startColumn]
calculateSums(startRow + 1, startColumn + 1, initialSum)
initialSum -= table[startRow][startColumn]
startColumn += 1
return max(totalSums)
f = random.randint(1, 7)
v = random.randint(f, 10)
# generate the number of flowers, f, and number of vases, v.
table = makeTable(f, v)
print('Number of flowers: ', f)
print('Number of vases: ', v)
printTable(table)
totalSums = []
print('Maximum sum is: ', calculateSums(0, 0, 0))
(I have a feeling that this is a stupid question, and possibly asked already, but I do not know how to search for it.)
In the above code calculateSums function will always receive the same arguments, thus it seems silly to pass them in. Yet I could not figure out how to manage them inside the function. What am I supposed to do?
You could use default parameters:
def calculateSums(startRow=0, startColumn=0, initialSum=0):
You can then make the initial call without parameters:
print('Maximum sum is: ', calculateSums())
However, be careful when using expressions in default arguments. These are calculated when the function is defined, not when it’s called.

Resources