├── JulianDayCalculator.py ├── ML_tools.py ├── MultiProcessing.py ├── PMT_count.py ├── Plot3dGraphic.py ├── README.md ├── Request.py ├── SinFunction.py ├── Socket.py ├── WGET.sh ├── avg_num_lst.py ├── create_file.py ├── ds_algos ├── 1d_dynamic │ ├── climbingStairs.py │ └── fibonacci.py ├── 2d_dynamic │ └── knapsack.py ├── arrays_hashTables │ ├── containsDup.py │ ├── groupAnagrams.py │ ├── twoSum.py │ └── validAnagram.py ├── backTracking copy │ ├── nQueens.py │ └── wordSearch.py ├── backTracking │ ├── nQueens.py │ └── wordSearch.py ├── fastAndSlow.py ├── graphs │ ├── graphGraphs │ │ └── graphIntro.py │ └── tree │ │ └── trie.py ├── prefixSum │ └── prefixSum.py ├── savingaFile.js ├── stacks │ ├── kFrequentEl.py │ └── validParens.py └── twoPointer │ ├── kadanes_algo.py │ ├── slidingWindow.py │ ├── targetSum.py │ ├── validPalindrome.py │ └── varyingSlidingWindow.py ├── fft.py ├── fft_data.txt ├── py_dict_demo.py ├── randomPolygonGenerator.py ├── relaxation_method.py ├── socket_2.py ├── statistics_admission_rates.py ├── string_manipulation.py └── vector_graphics.py /JulianDayCalculator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This program does... 5 | # 6 | # a. Prompts the user for a date in the form DDMmmYYYY. For example, 26Apr2016. 7 | # 8 | # b. Computes and prints the Julian day number corresponding to 0 h universal time 9 | # on the selected date 10 | # 11 | # c. Computes and prints the day of the week on which the selected date falls. 12 | # 13 | # ---Also, there are functions that are defined for each of the following tasks. 14 | # 15 | # a. Prompt the user and return his/her input string 16 | # 17 | # b. Parses the input string and returns a list containing the year, 18 | # month (1-12), and the day of the month. 19 | # 20 | # c. Compute the Julian day number using the list returned by the function from 21 | # the previous functions output 22 | # 23 | # d. Computes the day of the week given the julian day number 24 | # 25 | # 26 | 27 | #These are refrence lists and dictionaries for various parts of the code. 28 | 29 | month_abb = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 30 | days_of_week_dict = {0:'Sunday', 1:'Monday', 2:'Tuesday', 3:'Wednesday',4:'Thursday',5:'Friday',6:'Saturday'} 31 | month_code_dict = {'Jan':0,'Feb':3,'Mar':3,'Apr':6,'May':1,'Jun':4,'Jul':6,'Aug':2,'Sep':5,'Oct':0,'Nov':3,'Dec':5} 32 | cent_code_dict = {'17':4,'18':2,'19':0,'20':6,'21':4,'22':2,'23':0} 33 | leap_years = [i for i in range(0,2404,4)] 34 | 35 | #This function prompts the user, until the correct format is acheived. 36 | #I used a while loop and a conditional to break the while loop 37 | #The example provided provides clarity for any ambiguity for how to treate 38 | #single digit days and the month of September (Sep vs Sept) 39 | 40 | def prompt_user(): 41 | while True: 42 | print('Please enter a date of the form, DDMmmYYYY') 43 | print('An example is: 02Sep2022') 44 | print('\n') 45 | prompt = input('Enter your date here: ') 46 | print('\n') 47 | date_str = list(prompt) 48 | month_str = ''.join(date_str[2:5]) 49 | if month_str in month_abb and len(prompt) == 9: 50 | print(prompt) 51 | break 52 | return prompt 53 | 54 | #This function parses the strings with join() and string indexing. 55 | #This is why the above function keeps asking for a date given in the 56 | #correct format, since any other format would break this function. 57 | #I output string versions of the year and month for another function that 58 | #computes the days of the week in a different manner, not dependent on the julian day 59 | 60 | def string_parser(prompt): 61 | date_str = list(prompt) 62 | day = int(''.join(date_str[:2])) 63 | month_str = ''.join(date_str[2:5]) 64 | month_num = month_abb.index(month_str) + 1 65 | year_str = ''.join(date_str[5:]) 66 | year = int(year_str) 67 | date_lst = [year, month_num, day] 68 | print(date_lst) 69 | return month_str, year_str, date_lst 70 | 71 | #This is a function that computes the julian day with a formula. 72 | #It takes the prompt to simply print it out next to the output 73 | #of the computation so it is easier to read. 74 | 75 | def JD_calc(date_lst, prompt): 76 | D = date_lst[2] 77 | if date_lst[1] > 2: 78 | M = date_lst[1] 79 | Y = date_lst[0] 80 | JD = int(365.25*(Y + 4716)) + int(30.6001*(M + 1)) + D -1524.5 81 | elif date_lst[1] <=2: 82 | M = date_lst[1] + 12 83 | Y = year-1 84 | JD = int(365.25*(Y + 4716)) + int(30.6001*(M + 1)) + D -1524.5 85 | print('The Julian Day of '+ prompt +' is: '+ str(JD)) 86 | return JD 87 | 88 | #This is a function that computes what day of the week it is, 89 | #when given the julian day. 90 | 91 | #-note, it is much easier to calculate the day of the week given the julian day 92 | #than directly from the gregorian date 93 | 94 | def what_day_jd(JD): 95 | day_code = (JD +1.5)%7 96 | week_day = days_of_week_dict.get(day_code) 97 | print('This is a '+str(week_day)+ '!') 98 | return 99 | 100 | #This function calculates the day of a week given a specific gregorian date. 101 | #I made reference dictionaries that are commented out at the top of this program. 102 | #A nice thing about this function is that it does not depend on where you are in the 103 | #in the world. If you know what the gregorian date of you are interested, it gives 104 | #that date. It works too! The julian date calculator is a day early since it's 105 | #relative to the time in England. 106 | 107 | def what_day(day, month_str, year_str): 108 | YY = int(year_str[-2:]) 109 | y_code = (YY+(YY//4))%7 110 | m_code = int(month_code_dict.get(month_str)) 111 | yy = year_str[:2] 112 | yy_int = int(yy) 113 | if yy_int >= 17 or yy_int <=23: 114 | cent_code = int(cent_code_dict.get(yy)) 115 | else: 116 | cent_code = 0 117 | print('Cannot Compute the day of this date. Sorry : (') 118 | if int(year_str) in leap_years and month_str in ['Jan', 'Feb']: 119 | ly_code = -1 120 | else: 121 | ly_code = 0 122 | day_code = (y_code + m_code + cent_code + ly_code + day)%7 123 | week_day = days_of_week_dict.get(day_code) 124 | return(print('This is a '+str(week_day)+ '!')) 125 | 126 | 127 | #This is all the functions being called. 128 | 129 | prompt = prompt_user() 130 | 131 | month_str, year_str, date_lst = string_parser(prompt) 132 | 133 | JD = JD_calc(date_lst, prompt) 134 | 135 | #what_day(date_lst[2], month_str, year_str) 136 | 137 | what_day_jd(JD) 138 | -------------------------------------------------------------------------------- /ML_tools.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This is a list of machine learning tools to be used on various datasets. 5 | # There are function that utilize iterative loops as well as vectorized 6 | # functions for increase performance. 7 | 8 | import numpy as np 9 | 10 | # Loop version of multi-variable compute_cost 11 | def compute_cost(X, y, w, b): 12 | """ 13 | compute cost 14 | Args: 15 | X (ndarray (m,n)): Data, m examples with n features 16 | y (ndarray (m,)) : target values 17 | w (ndarray (n,)) : model parameters 18 | b (scalar) : model parameter 19 | Returns 20 | cost (scalar) : cost 21 | """ 22 | m = X.shape[0] 23 | cost = 0.0 24 | for i in range(m): 25 | f_wb_i = np.dot(X[i],w) + b #(n,)(n,)=scalar 26 | cost = cost + (f_wb_i - y[i])**2 27 | cost = cost/(2*m) 28 | return cost 29 | 30 | #Function to calculate the cost 31 | 32 | def compute_lin_cost_matrix(X, y, w, b, verbose=False): 33 | """ 34 | Computes the gradient for linear regression 35 | Args: 36 | X (ndarray (m,n)): Data, m examples with n features 37 | y (ndarray (m,)) : target values 38 | w (ndarray (n,)) : model parameters 39 | b (scalar) : model parameter 40 | verbose : (Boolean) If true, print out intermediate value f_wb 41 | Returns 42 | cost: (scalar) 43 | """ 44 | m = X.shape[0] 45 | 46 | # calculate f_wb for all examples. 47 | f_wb = X @ w + b 48 | # calculate cost 49 | total_cost = (1/(2*m)) * np.sum((f_wb-y)**2) 50 | 51 | if verbose: print("f_wb:") 52 | if verbose: print(f_wb) 53 | 54 | return total_cost 55 | 56 | def compute_logistic_cost_matrix(X, y, w, b, logistic=False, lambda_=0, safe=True): 57 | """ 58 | Computes the cost using using matrices 59 | Args: 60 | X : (ndarray, Shape (m,n)) matrix of examples 61 | y : (ndarray Shape (m,) or (m,1)) target value of each example 62 | w : (ndarray Shape (n,) or (n,1)) Values of parameter(s) of the model 63 | b : (scalar ) Values of parameter of the model 64 | verbose : (Boolean) If true, print out intermediate value f_wb 65 | Returns: 66 | total_cost: (scalar) cost 67 | """ 68 | m = X.shape[0] 69 | y = y.reshape(-1,1) # ensure 2D 70 | w = w.reshape(-1,1) # ensure 2D 71 | if logistic: 72 | if safe: #safe from overflow 73 | z = X @ w + b #(m,n)(n,1)=(m,1) 74 | cost = -(y * z) + log_1pexp(z) 75 | cost = np.sum(cost)/m # (scalar) 76 | else: 77 | f = sigmoid(X @ w + b) # (m,n)(n,1) = (m,1) 78 | cost = (1/m)*(np.dot(-y.T, np.log(f)) - np.dot((1-y).T, np.log(1-f))) # (1,m)(m,1) = (1,1) 79 | cost = cost[0,0] # scalar 80 | else: 81 | f = X @ w + b # (m,n)(n,1) = (m,1) 82 | cost = (1/(2*m)) * np.sum((f - y)**2) # scalar 83 | 84 | reg_cost = (lambda_/(2*m)) * np.sum(w**2) # scalar 85 | 86 | total_cost = cost + reg_cost # scalar 87 | 88 | return total_cost # scalar 89 | 90 | 91 | 92 | def compute_cost_logistic(X, y, w, b, lambda_=0, safe=False): 93 | """ 94 | Computes cost using logistic loss, non-matrix version 95 | 96 | Args: 97 | X (ndarray): Shape (m,n) matrix of examples with n features 98 | y (ndarray): Shape (m,) target values 99 | w (ndarray): Shape (n,) parameters for prediction 100 | b (scalar): parameter for prediction 101 | lambda_ : (scalar, float) Controls amount of regularization, 0 = no regularization 102 | safe : (boolean) True-selects under/overflow safe algorithm 103 | Returns: 104 | cost (scalar): cost 105 | """ 106 | 107 | m,n = X.shape 108 | cost = 0.0 109 | for i in range(m): 110 | z_i = np.dot(X[i],w) + b #(n,)(n,) or (n,) () 111 | if safe: #avoids overflows 112 | cost += -(y[i] * z_i ) + log_1pexp(z_i) 113 | else: 114 | f_wb_i = sigmoid(z_i) #(n,) 115 | cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i) # scalar 116 | cost = cost/m 117 | 118 | reg_cost = 0 119 | if lambda_ != 0: 120 | for j in range(n): 121 | reg_cost += (w[j]**2) # scalar 122 | reg_cost = (lambda_/(2*m))*reg_cost 123 | 124 | return cost + reg_cost # scalar 125 | 126 | 127 | 128 | def compute_gradient(X, y, w, b): 129 | """ 130 | Computes the gradient for linear regression 131 | Args: 132 | X (ndarray (m,n)): Data, m examples with n features 133 | y (ndarray (m,)) : target values 134 | w (ndarray (n,)) : model parameters 135 | b (scalar) : model parameter 136 | Returns 137 | dj_dw (ndarray Shape (n,)): The gradient of the cost w.r.t. the parameters w. 138 | dj_db (scalar): The gradient of the cost w.r.t. the parameter b. 139 | """ 140 | m,n = X.shape #(number of examples, number of features) 141 | dj_dw = np.zeros((n,)) 142 | dj_db = 0. 143 | 144 | for i in range(m): 145 | err = (np.dot(X[i], w) + b) - y[i] 146 | for j in range(n): 147 | dj_dw[j] = dj_dw[j] + err * X[i,j] 148 | dj_db = dj_db + err 149 | dj_dw = dj_dw/m 150 | dj_db = dj_db/m 151 | 152 | return dj_db, 153 | 154 | def compute_gradient_logistic(X, y, w, b): 155 | """ 156 | Computes the gradient for linear regression 157 | 158 | Args: 159 | X (ndarray (m,n): Data, m examples with n features 160 | y (ndarray (m,)): target values 161 | w (ndarray (n,)): model parameters 162 | b (scalar) : model parameter 163 | Returns 164 | dj_dw (ndarray (n,)): The gradient of the cost w.r.t. the parameters w. 165 | dj_db (scalar) : The gradient of the cost w.r.t. the parameter b. 166 | """ 167 | m,n = X.shape 168 | dj_dw = np.zeros((n,)) #(n,) 169 | dj_db = 0. 170 | 171 | for i in range(m): 172 | x_i = np.dot(X[i],w) + b 173 | f_wb_i = sigmoid(x_i) #(n,)(n,)=scalar 174 | err_i = f_wb_i - y[i] #scalar 175 | for j in range(n): 176 | dj_dw[j] = dj_dw[j] + err_i * X[i,j] #scalar 177 | dj_db = dj_db + err_i 178 | dj_dw = dj_dw/m #(n,) 179 | dj_db = dj_db/m #scalar 180 | 181 | return dj_db, dj_dw 182 | 183 | def compute_gradient_matrix(X, y, w, b): 184 | """ 185 | Computes the gradient for linear regression 186 | 187 | Args: 188 | X (ndarray (m,n)): Data, m examples with n features 189 | y (ndarray (m,)) : target values 190 | w (ndarray (n,)) : model parameters 191 | b (scalar) : model parameter 192 | Returns 193 | dj_dw (ndarray (n,1)): The gradient of the cost w.r.t. the parameters w. 194 | dj_db (scalar): The gradient of the cost w.r.t. the parameter b. 195 | 196 | """ 197 | m,n = X.shape 198 | f_wb = X @ w + b 199 | e = f_wb - y 200 | dj_dw = (1/m) * (X.T @ e) 201 | dj_db = (1/m) * np.sum(e) 202 | 203 | return dj_db,dj_dw 204 | 205 | def gradient_descent(X, y, w_in, b_in, cost_function, gradient_function, alpha, num_iters): 206 | ''' 207 | Performs batch gradient descent to learn theta. Updates theta by taking 208 | num_iters gradient steps with learning rate alpha 209 | 210 | Args: 211 | X : (array_like Shape (m,n) matrix of examples 212 | y : (array_like Shape (m,)) target value of each example 213 | w_in : (array_like Shape (n,)) Initial values of parameters of the model 214 | b_in : (scalar) Initial value of parameter of the model 215 | cost_function: function to compute cost 216 | gradient_function: function to compute the gradient 217 | alpha : (float) Learning rate 218 | num_iters : (int) number of iterations to run gradient descent 219 | Returns 220 | w : (array_like Shape (n,)) Updated values of parameters of the model after 221 | running gradient descent 222 | b : (scalar) Updated value of parameter of the model after 223 | running gradient descent 224 | ''' 225 | 226 | # number of training examples 227 | m = len(X) 228 | 229 | # An array to store values at each iteration primarily for graphing later 230 | hist={} 231 | hist["cost"] = []; hist["params"] = []; hist["grads"]=[]; hist["iter"]=[]; 232 | 233 | w = copy.deepcopy(w_in) #avoid modifying global w within function 234 | b = b_in 235 | save_interval = np.ceil(num_iters/10000) # prevent resource exhaustion for long runs 236 | 237 | for i in range(num_iters): 238 | 239 | # Calculate the gradient and update the parameters 240 | dj_db,dj_dw = gradient_function(X, y, w, b) 241 | 242 | # Update Parameters using w, b, alpha and gradient 243 | w = w - alpha * dj_dw 244 | b = b - alpha * dj_db 245 | 246 | # Save cost J,w,b at each save interval for graphing 247 | if i == 0 or i % save_interval == 0: 248 | hist["cost"].append(cost_function(X, y, w, b)) 249 | hist["params"].append([w,b]) 250 | hist["grads"].append([dj_dw,dj_db]) 251 | hist["iter"].append(i) 252 | 253 | # Print cost every at intervals 10 times or as many iterations if < 10 254 | if i% math.ceil(num_iters/10) == 0: 255 | #print(f"Iteration {i:4d}: Cost {cost_function(X, y, w, b):8.2f} ") 256 | cst = cost_function(X, y, w, b) 257 | print(f"Iteration {i:9d}, Cost: {cst:0.5e}") 258 | return w, b, hist #return w,b and history for graphing 259 | 260 | def gradient_descent(X, y, w_in, b_in, alpha, num_iters): 261 | ''' 262 | Performs batch gradient descent 263 | 264 | Args: 265 | X (ndarray (m,n) : Data, m examples with n features 266 | y (ndarray (m,)) : target values 267 | w_in (ndarray (n,)): Initial values of model parameters 268 | b_in (scalar) : Initial values of model parameter 269 | alpha (float) : Learning rate 270 | num_iters (scalar) : number of iterations to run gradient descent 271 | 272 | Returns: 273 | w (ndarray (n,)) : Updated values of parameters 274 | b (scalar) : Updated value of parameter 275 | ''' 276 | # An array to store cost J and w's at each iteration primarily for graphing later 277 | J_history = [] 278 | w = copy.deepcopy(w_in) #avoid modifying global w within function 279 | b = b_in 280 | 281 | for i in range(num_iters): 282 | # Calculate the gradient and update the parameters 283 | dj_db, dj_dw = compute_gradient_logistic(X, y, w, b) 284 | 285 | # Update Parameters using w, b, alpha and gradient 286 | w = w - alpha * dj_dw 287 | b = b - alpha * dj_db 288 | 289 | # Save cost J at each iteration 290 | if i<100000: # prevent resource exhaustion 291 | J_history.append(compute_cost_logistic(X, y, w, b) ) 292 | 293 | # Print cost every at intervals 10 times or as many iterations if < 10 294 | if i% math.ceil(num_iters / 10) == 0: 295 | print(f"Iteration {i:4d}: Cost {J_history[-1]} ") 296 | 297 | return w, b, J_history #return final w,b and J history for graphing 298 | 299 | 300 | 301 | 302 | def zscore_normalize_features(X,rtn_ms=False): 303 | ''' 304 | returns z-score normalized X by column 305 | Args: 306 | X : (numpy array (m,n)) 307 | Returns 308 | X_norm: (numpy array (m,n)) input normalized by column 309 | ''' 310 | mu = np.mean(X,axis=0) 311 | sigma = np.std(X,axis=0) 312 | X_norm = (X - mu)/sigma 313 | 314 | if rtn_ms: 315 | return(X_norm, mu, sigma) 316 | else: 317 | return(X_norm) 318 | 319 | def log_1pexp(x, maximum=20): 320 | ''' approximate log(1+exp^x) 321 | https://stats.stackexchange.com/questions/475589/numerical-computation-of-cross-entropy-in-practice 322 | Args: 323 | x : (ndarray Shape (n,1) or (n,) input 324 | out : (ndarray Shape matches x output ~= np.log(1+exp(x)) 325 | ''' 326 | 327 | out = np.zeros_like(x,dtype=float) 328 | i = x <= maximum 329 | ni = np.logical_not(i) 330 | 331 | out[i] = np.log(1 + np.exp(x[i])) 332 | out[ni] = x[ni] 333 | return out 334 | 335 | def sigmoid(x): 336 | return 1/(1 + np.exp(-x)) 337 | -------------------------------------------------------------------------------- /MultiProcessing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # William Murphy 4 | # 22May22 5 | 6 | # This program compares optimizxation techniques 7 | # on computing the mandelbrot set, and computes a 8 | # super hi-resolution plot with the most optimized 9 | # method 10 | 11 | import time 12 | import numpy as np 13 | import numexpr as ne 14 | import multiprocessing as mp 15 | import matplotlib.pyplot as plt 16 | from matplotlib import cm 17 | 18 | # Parameters of all the funcitons run 19 | 20 | x_min = -00.73 21 | x_max = -0.805 22 | y_min = 0.01 23 | y_max = 0.17 24 | 25 | x_mid = (x_max - x_min)/2 26 | y_mid = (y_max - y_min)/2 27 | 28 | width = 512 29 | height = 384 30 | max_iter = 1000 31 | 32 | width_a = 1024 33 | height_a = 768 34 | 35 | width_b = 4096*2 36 | height_b = 3072*2 37 | 38 | h_width = width//2 39 | h_height = height//2 40 | 41 | # List for storing data to be plotted 42 | processes_lst = [] 43 | 44 | iter_lst = range(100,2001,100) 45 | 46 | timeit_lst_serial = [] 47 | timeit_lst_vect = [] 48 | timeit_lst_static = [] 49 | timeit_lst_ne = [] 50 | 51 | timeit_lst_seriala = [] 52 | timeit_lst_vecta = [] 53 | timeit_lst_statica = [] 54 | timeit_lst_nea = [] 55 | 56 | #This line makes sure that the the data is sectioned in the middle 57 | num_cpu = 4 58 | 59 | # Computes the mandelbrot/ parts of the set 60 | # This is the same program that was turned for p5_hw5 61 | 62 | def mandel_serial(x_min, x_max, y_min, y_max, width, height, max_iter): 63 | 64 | mandel_arr = np.ones((width, height, 3), dtype='uint8') 65 | 66 | # Need to comput half the array since it's broken up 67 | re = np.linspace(x_min, x_max, width) 68 | im = np.linspace(y_min, y_max, height) 69 | 70 | color_arr = np.array(([1,1,1,1])) 71 | color_sch = cm.get_cmap('magma') 72 | 73 | for i in range(width): 74 | for k in range(height): 75 | c = complex(re[i],im[k]) 76 | m, z = 0, 0 77 | while abs(z) <= 2 and m <= max_iter: 78 | z = z*z + c 79 | m += 1 80 | color = round(float(1-(m/max_iter)), 2) 81 | pix_color = color_arr * color_sch(color)*255 82 | mandel_arr[i,k,:] = pix_color[0:3].astype(int) 83 | 84 | return mandel_arr 85 | 86 | # Everything below is for Multiprocessing/Optimization 87 | 88 | ############################################################################# 89 | 90 | # Vectorized version of the mandel_serial 91 | 92 | def mandel_vect(x_min, x_max, y_min, y_max, width, height, max_iter): 93 | 94 | re = np.linspace(x_min, x_max, width).reshape((1, width)) 95 | im = np.linspace(y_min, y_max, height).reshape((height, -1)) 96 | c = re + 1j * im 97 | z = np.zeros(c.shape, dtype='complex128') 98 | 99 | # Keeping track of how many iterations it to diverge 100 | div_num = np.zeros(c.shape, dtype=int) 101 | 102 | # Keeping this for loop as small as possible and using arrays 103 | # and array indexing to do all computation in parallel and 104 | # in C 105 | 106 | for i in range(max_iter): 107 | in_set = np.less(z.real*z.real+z.imag*z.imag, 3) 108 | div_num[in_set] = i 109 | z[in_set] = z[in_set]**2 + c[in_set] 110 | 111 | return div_num 112 | 113 | ############################################################################## 114 | 115 | # This is a helper function to place the data in a dictionary and process it at the same time 116 | # This is known as inter process communication 117 | 118 | def data_queue( x_min, x_max, y_min, y_max, width, height, max_iter, Queue, key): 119 | mandel_arr = mandel_vect(x_min, x_max, y_min, y_max, width, height, max_iter) 120 | return Queue.put({key : mandel_arr}) 121 | 122 | # The function that parallelizes the processing 123 | 124 | def mandel_static_mp(x_max, x_min, y_min, y_max, width, height, max_iter): 125 | # Using a queue to organize data 126 | mandel_data = mp.Queue() 127 | processes_lst = [] 128 | 129 | # This dictionary organizes the data according to which core it was computed on 130 | data_dict = {} 131 | 132 | #min_iter = max_iter // 4 133 | #Divides the compute power among the 4 cores of the ras-pi 134 | 135 | p0 = mp.Process(target=data_queue, args=(x_min, x_min + x_mid, y_min, y_min + y_mid, width, height, max_iter, mandel_data, 0)) 136 | p0.start() 137 | processes_lst.append(p0) 138 | 139 | p1 = mp.Process(target=data_queue, args=(x_min + x_mid, x_max, y_min, y_min + y_mid, width, height, max_iter, mandel_data, 1)) 140 | p1.start() 141 | processes_lst.append(p1) 142 | 143 | p2 = mp.Process(target=data_queue, args=(x_min, x_min + x_mid, y_min + y_mid, y_max, width, height, max_iter, mandel_data, 2)) 144 | p2.start() 145 | processes_lst.append(p2) 146 | 147 | p3 = mp.Process(target=data_queue, args=(x_min + x_mid, x_max, y_min + y_mid, y_max, width, height, max_iter, mandel_data, 3)) 148 | p3.start() 149 | processes_lst.append(p3) 150 | 151 | # Getting the data from the dictionary ready to be joined 152 | for i in processes_lst: 153 | data_dict.update(mandel_data.get()) 154 | 155 | bot_arr = np.concatenate((data_dict[0], data_dict[2]), axis=0) 156 | top_arr = np.concatenate((data_dict[1], data_dict[3]), axis=0) 157 | 158 | mandel_arr = np.concatenate((bot_arr,top_arr), axis=1) 159 | 160 | for p in processes_lst: 161 | p.join() 162 | 163 | return mandel_arr 164 | 165 | ################################################################################ 166 | 167 | # This algorithm is very similar to my mandel_vect(), only now 168 | # it uses numexpr to evaluate inside the for loop 169 | 170 | # using numexpr instead of numpy means that temporary arrays are 171 | # not created and arrays are processed on multiple cores. 172 | 173 | def mandel_ne(x_min, x_max, y_min, y_max, width, height, max_iter): 174 | 175 | #Mapping the complex plane onto the area to be graphed 176 | re = np.linspace(x_min, x_max, width).reshape((1, width)) 177 | im = np.linspace(y_min, y_max, height).reshape((height, -1)) 178 | c = re + 1j * im 179 | 180 | # Initialize z to all zeros 181 | z = np.zeros(c.shape, dtype='complex128') 182 | 183 | # To keep track when the iteration diverged 184 | div_num = np.zeros(c.shape, dtype=int) 185 | 186 | # Keeping this for loop as small as possible, using numexpr 187 | # instead of numpy so temporary arrays are not created and 188 | # arrays are processed on multiple cores. 189 | for i in range(max_iter): 190 | in_set = ne.evaluate('z.real**2 + z.imag**2 < 2') 191 | div_num[in_set] = i 192 | z = ne.evaluate('where(in_set,z**2+c,z)') 193 | 194 | return div_num 195 | 196 | 197 | # Program to compare functions 198 | 199 | if __name__ == '__main__': 200 | 201 | # Makes the mandelbort set 202 | mandel_arr = mandel_ne(x_min, x_max, y_min, y_max, width_b, height_b, max_iter) 203 | 204 | 205 | string_for_data_output = ''' 206 | for i in iter_lst: 207 | 208 | 209 | # Lower Resolution function calls 210 | 211 | t0 = time.perf_counter() 212 | mandel_serial(x_min, x_max, y_min, y_max, width, height, i) 213 | t1 = time.perf_counter() 214 | t_1 = t1 - t0 215 | timeit_lst_serial.append(t_1) 216 | 217 | ta = time.perf_counter() 218 | mandel_vect(x_min, x_max, y_min, y_max, width, height, i) 219 | tb = time.perf_counter() 220 | t_a = tb - ta 221 | timeit_lst_vect.append(t_a) 222 | 223 | t2 = time.perf_counter() 224 | mandel_static_mp(x_min, x_max, y_min, y_max, width, height, i) 225 | t3 = time.perf_counter() 226 | t_2 = t3 - t2 227 | timeit_lst_static.append(t_2) 228 | 229 | t4 = time.perf_counter() 230 | mandel_ne(x_min, x_max, y_min, y_max, width, height, i) 231 | t5 = time.perf_counter() 232 | t_3 = t5 - t4 233 | timeit_lst_ne.append(t_3) 234 | 235 | # Higher Resolution function calls 236 | 237 | t0a = time.perf_counter() 238 | mandel_serial(x_min, x_max, y_min, y_max, width_a, height_a, i) 239 | t1a = time.perf_counter() 240 | t_1a = t1a - t0a 241 | timeit_lst_seriala.append(t_1a) 242 | 243 | tc = time.perf_counter() 244 | mandel_vect(x_min, x_max, y_min, y_max, width_a, height_a, i) 245 | td = time.perf_counter() 246 | t_b = td - tc 247 | timeit_lst_vecta.append(t_b) 248 | 249 | t2a = time.perf_counter() 250 | mandel_static_mp(x_min, x_max, y_min, y_max, width_a, height_a, i) 251 | t3a = time.perf_counter() 252 | t_2a = t3a - t2a 253 | timeit_lst_statica.append(t_2a) 254 | 255 | t4a = time.perf_counter() 256 | mandel_ne(x_min, x_max, y_min, y_max, width_a, height_a, i) 257 | t5a = time.perf_counter() 258 | t_3a = t5a - t4a 259 | timeit_lst_nea.append(t_3a) 260 | 261 | ''' 262 | 263 | fig, ax = plt.subplots()#(1,2) 264 | 265 | string_plotting_figures = ''' 266 | fig.suptitle('Compute times for various methods of computing the mandelbrot set') 267 | 268 | #Lower resolutions data plot 269 | 270 | p1, =ax[0].plot(iter_lst, timeit_lst_serial,label="Serial") 271 | pa, =ax[0].plot(iter_lst, timeit_lst_vect,label="Vectorized Serial") 272 | p2, =ax[0].plot(iter_lst, timeit_lst_static,label="Static Multiprocessing") 273 | p3, =ax[0].plot(iter_lst, timeit_lst_ne,label="NumExpr") 274 | ax[0].set_title('Low Resolution') 275 | ax[0].set_xlabel('Interations') 276 | ax[0].set_ylabel('Time Elapsed (s)') 277 | ax[0].legend(loc='best') 278 | 279 | 280 | # Higher resolution data plot 281 | 282 | p1a, =ax[1].plot(iter_lst, timeit_lst_seriala,label="Serial") 283 | pb, =ax[1].plot(iter_lst, timeit_lst_vecta,label="Vectorized Serial") 284 | p2a, =ax[1].plot(iter_lst, timeit_lst_statica,label="Static Multiprocessing") 285 | p3a, =ax[1].plot(iter_lst, timeit_lst_nea,label="NumExpr") 286 | 287 | ax[1].set_title('High Resolution') 288 | ax[1].set_xlabel('Interations') 289 | ax[1].set_ylabel('Time Elapsed (s)') 290 | ax[1].legend(loc='best') 291 | ''' 292 | sup_hi_res = mandel_ne(x_min, x_max, y_min, y_max, width_a, height_a, 1000) 293 | ax.axis('off') 294 | ax.imshow(sup_hi_res, cmap='magma') 295 | 296 | plt.show() 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /PMT_count.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This program does 4 | 5 | # a) Has a function which simulates photon counting for 1000 one-millisecond 6 | # intervals, with the probability of a detection in each interval being 0.002. 7 | # The function should return the total number of detections. 8 | 9 | # b) Plots a histogram displaying the result of calling the function 1000 times 10 | 11 | # c) overlays on the plot, in a different color, a graph of the Poisson distribution 12 | # with mean, standard deviation, and maximum value corresponding to this simulation. 13 | 14 | 15 | import numpy as np 16 | import random 17 | import matplotlib.pyplot as plt 18 | import scipy.stats as stats 19 | 20 | 21 | # This function counts two numbers out of 1000 possible 22 | # numbers to choose from. If one of the two is chosen, 23 | # 1 is added to the counting variable. 24 | 25 | #NOTE- The two numbers choose for this program have no 26 | # special purpose. 27 | 28 | def counting_photons(N): 29 | photon_num = 0 30 | for i in range(N+1): 31 | x = random.randint(0, 1000) 32 | if x in [271, 277]: 33 | photon_num += 1 34 | else: 35 | pass 36 | return photon_num 37 | 38 | #num_photons = counting_photons(1000) 39 | #print(num_photons) 40 | 41 | # This functions calls the previous function 42 | # 1000 times. After each call, it stores the output 43 | # into a list, so it can later be plotted. 44 | 45 | def counting_counted_photons(trials): 46 | outcome = [] 47 | for i in range(trials): 48 | outcome.append(counting_photons(1000)) 49 | return outcome 50 | 51 | 52 | #Creating a Poisson Fit 53 | outcome_lst = counting_counted_photons(1000) 54 | mean = np.mean(outcome_lst) 55 | data_max = np.max(outcome_lst) 56 | sd = round(np.std(outcome_lst), 3) 57 | print(data_max) 58 | 59 | x = np.arange(0,5, 0.01) 60 | pmf = stats.poisson.pmf(x, mean) 61 | 62 | # Plotting 63 | fig, ax = plt.subplots() 64 | 65 | ax.plot(x,pmf, color='red') 66 | 67 | ax.hist(outcome_lst, density=True, facecolor='g', alpha=0.75) 68 | 69 | ax.set_title('Histogram of 1000 trials of \n counting photons for 1000 miliseconds') 70 | 71 | ax.text(5,0.25,'Max Value: '+str(data_max)+'\n \u03BC = '+str(mean)+'\n \u03C3 = '+str(sd)) 72 | ax.set_xlabel('Number of Photons Counted') 73 | ax.set_ylabel('Probability') 74 | ax.grid(True) 75 | plt.show() 76 | -------------------------------------------------------------------------------- /Plot3dGraphic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Author -- William Murphy 4 | # Date -- 04May2022 5 | 6 | 7 | # Plotting the function z(x,y) = sin(x)cos(y) 8 | 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | from mpl_toolkits import mplot3d 12 | 13 | 14 | # Compute z_func to make the surface. 15 | def func_z(x,y): 16 | return np.sin(x)*np.cos(y) 17 | 18 | #Define the space we are solving for z 19 | x = np.linspace(0, 5*np.pi, 900) 20 | y = np.linspace(0, 5*np.pi, 900) 21 | 22 | #Creating amesh grid for the points in the set z 23 | X, Y = np.meshgrid(x, y) 24 | Z = func_z(X, Y) 25 | 26 | 27 | #Making the 3D space 28 | fig = plt.figure() 29 | ax = plt.axes(projection="3d") 30 | 31 | #Setting labels and title 32 | ax.set_xlabel('x') 33 | ax.set_ylabel('y') 34 | ax.set_zlabel('z') 35 | ax.set_title('z(x,y)=sin(x)cos(y)') 36 | 37 | #The requested method - plot_surface() 38 | ax.plot_surface(X,Y,Z, cmap='cividis') 39 | 40 | plt.show() 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python_projects 2 | 3 | This is an assortment of fun projects that goes over different methods of scientific computing in python. The projects range from programs that solve any static differential equations, to fourier transformations, and more advanced ideas of scientific computing like multiprocessing and vercotization of algorithms. It is not only calculations though, some files also include component hardware like solar cells, and thermometers. 4 | 5 | In addtion to the scientific computing programs, the repo also includes a file that calculates regressions and imple neural networks from scratch. 6 | 7 | Thanks for taking a look, and if you have any questions, feel free to reach out. 8 | -------------------------------------------------------------------------------- /Request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import requests 5 | 6 | r = requests.get('https://web.physics.ucsb.edu/~phys129/lipman/', auth=('user', 'pass'), headers={'Connection':'close'}) 7 | 8 | #Makng the html text a string 9 | html_txt = str(r.text) 10 | 11 | #Finding parsing the string for the desired line 12 | begin_where = html_txt.find('Latest update') 13 | end_where = html_txt.find('

')-7 14 | update_str = html_txt[begin_where:end_where] 15 | 16 | #Deleting the undesired text form the desired line 17 | last_update = update_str.replace('','').replace(' ',' ') 18 | 19 | print('') 20 | print('Physics 129L '+last_update) 21 | print('') 22 | -------------------------------------------------------------------------------- /SinFunction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | 5 | # This is program that does a few different things 6 | 7 | 8 | 9 | # a. Prompts the user for a non-zero angle in degrees 10 | 11 | # b. Continues to reprompt the user unless the input is acceptable 12 | 13 | # c. Prompts the user for a number, ≤ 25, of terms to sum in a series 14 | 15 | # d. Continues to reprompt the user unless the input is acceptable 16 | 17 | # e. Calculates, using a function you have defined called sind(), the sine of the angle 18 | 19 | # provided by the user. This function must sum a series to the number of terms 20 | 21 | # requested, and may not use any predefined Python math functions. 22 | 23 | # f. Calculates the sine of the angle using math.sin() 24 | 25 | # g. Prints out a quantitative comparison between the two answers including the ratio 26 | 27 | # and the absolute difference. 28 | 29 | 30 | import math as m 31 | 32 | #This is a function that can tell if a string is a float or not. 33 | 34 | def isfloat(num): 35 | try: 36 | float(num) 37 | return True 38 | except ValueError: 39 | return False 40 | 41 | #A while loop that continues the prompt the users, unless they put in a 42 | #data type that can be turned into a float. 43 | #I called the above function here to make the code easier to read. 44 | #Further, within this while loop, I calculated the degrees into radians as 45 | #soon as I could since I would be needed to work in them for the rest of the 46 | #the program. 47 | 48 | while True: 49 | prompt_1 = input('Please enter an angle in degrees you are interested in: ') 50 | q = isfloat(prompt_1) 51 | if q == True: 52 | radians = float(prompt_1)/180 * m.pi 53 | break 54 | 55 | #I used the same structure of a while loop plus a conditional here as well, 56 | #to get the user to input an integer for the length of the series. 57 | 58 | while True: 59 | prompt_2 = input('Please enter a non-zero integer less than or equal to 25: ') 60 | if prompt_2.isdigit() == True: 61 | if int(prompt_2) <= 25: 62 | series_len = abs(int(prompt_2)) 63 | break 64 | 65 | #Since we are not using any pre built functions from python, I built my own 66 | #factorial function. Strictly speaking, if I was building a more general purpose 67 | #factorial function I would disqualify negative number, but I already did this 68 | #in this while loop above. Ii did however define 0! = 1 though, to avoid a zero 69 | #division error 70 | 71 | def factorial(num): 72 | f = 1 73 | if num == 0: 74 | f == 1 75 | else: 76 | for i in range(1, num + 1): 77 | f = f * i 78 | return f 79 | 80 | #This is the requested sind() function. It takes the users inputs and computes 81 | #the first 'prompt_2' terms of the sin(prompt_1) taylor series. It calls the 82 | #factorial function that was created above to keep the code cleaner 83 | 84 | def sind(rad, series_len): 85 | sin = 0 86 | for i in range(0, series_len, 1): 87 | n = 2*i+1 88 | sin = sin + (((-1)**(i))*(rad**(n))/(factorial(n))) 89 | print(sin) 90 | return sin 91 | 92 | 93 | #Outputs 94 | 95 | 96 | sin_me = sind(radians, series_len) 97 | sin_math = m.sin(radians) 98 | 99 | print("My sine function's output is "+str(sin_me)) 100 | print('\n') 101 | 102 | print("Python's math module output is "+str(sin_math)) 103 | print('\n') 104 | 105 | print("The ratio of my function's output over python's math module's is "+str(sin_me/sin_math)) 106 | print('\n') 107 | 108 | abs_dif = abs(sin_me - sin_math) 109 | 110 | print('The absolute difference between the two is '+str(abs_dif)) 111 | print('\n') 112 | 113 | -------------------------------------------------------------------------------- /Socket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | #Sockets and Requests 4 | 5 | import socket 6 | 7 | host = "web.physics.ucsb.edu" 8 | port = 80 9 | 10 | # creating a socket 11 | thesocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | 13 | # connecting to the client 14 | thesocket.connect((host,port)) 15 | 16 | # Making a request for HTTP data 17 | request = "GET /~phys129/lipman/ HTTP/1.1\r\nHost:%s\r\n\r\n" % host 18 | thesocket.send(request.encode()) 19 | 20 | # Receiving the HTTP data and closing the socket 21 | response = thesocket.recv(4096) 22 | http_response = str(repr(response)) 23 | thesocket.shutdown(socket.SHUT_RDWR) 24 | thesocket.close() 25 | 26 | #Parsing the HTTP data for the desired text 27 | begining = http_response.find('Latest update') 28 | ending = http_response.find('

') 29 | Latest_update = http_response[begining:ending].replace('','').replace(' ',' ') 30 | 31 | #The output 32 | print('') 33 | print('Physics 129L '+Latest_update) 34 | print('') 35 | -------------------------------------------------------------------------------- /WGET.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | 5 | # Author : WIlliam Murphy 6 | # Date : 03May22 7 | 8 | # This shell script makes a request to physics 129L course web pages and 9 | # returns when the latest update occured on the anoucemnets page. 10 | 11 | # This shell script implements the commands - 'wget', 'grep', 'sed' 12 | 13 | 14 | wget -O- web.physics.ucsb.edu/~phys129/lipman/ | grep -h "Latest update" | sed -e 's///' -e 's/ / /' -e 's/<\/span><\/p>//' 15 | 16 | 17 | -------------------------------------------------------------------------------- /avg_num_lst.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # A program that reads numbers from a user-specified 4 | # file and prints out their average 5 | # note - input file requires one number per line 6 | 7 | # Author - Billy Murphy 8 | # 12 April 2022 9 | 10 | 11 | import numpy as np 12 | 13 | 14 | #Prompting the user for the name of file to operate on. 15 | 16 | fname = input('What is the file you would like to read: ') 17 | 18 | #Reading the text file and returning the contents as a list. 19 | #Each item of the list represents a line of the file. 20 | 21 | infile = open(str(fname), 'r') 22 | lines = infile.readlines() 23 | 24 | #Because the output of lines is has the new line character 25 | #a for loop is used to remove it from each item of of lines and 26 | #and appends the cleaned string to str_lst. This allows for numbers with 27 | #more than one digit. 28 | 29 | str_lst = [] 30 | for line in lines: 31 | i = line.rstrip("\n") 32 | str_lst.append(i) 33 | 34 | #Because there is no string.isdigit() method, I am using a 35 | #a function that can tell if a sting is float or not. 36 | #It has a simply True or False output and is used later. 37 | def isfloat(num): 38 | try: 39 | float(num) 40 | return True 41 | except ValueError: 42 | return False 43 | 44 | #This for loop populates a list that can be operatored on by numpy. Within this for loop 45 | #are some conditionals statements that handle the different types of characters that are 46 | #possible. Namely letters, numbers, and special characters. I included this extra bit to make 47 | #program robust to errors within the data it is analyzing. I don't want to rely on 48 | #the input data to be in a perfect format for the practical reason that often times real world 49 | #data is quite messy. 50 | 51 | num_lst = [] 52 | for i in str_lst : 53 | if i.isdigit() == True: 54 | num_lst.append(float(i)) 55 | elif isfloat(str(i)) == True: 56 | num_lst.append(float(i)) 57 | elif isfloat(str(i)) == False: 58 | print('ERROR: '+str(i)+' was skipped because it is not a number.') 59 | 60 | #The program prints the average of the given file. 61 | print('The average is: '+str(np.average(num_lst))) 62 | 63 | #As an add feature to the program I made it so that if there is a mistake 64 | #in the original file, the code with skip over that entry and alert the user 65 | #that there is an entry that was skipped. 66 | 67 | #Closing the file. This may seem like a trivial comment, though for the sake of explination I am including this time. I the program did not close the file, there is all kinds of mysterious and troublesome problems that could arise from the leaving a file open. Most likely the file would become currupted. This would obviously be a terrible thing. To write a program that corrupts files is pretty much a fail. Especially since you might not notice it right away! 68 | infile.close() 69 | 70 | -------------------------------------------------------------------------------- /create_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is a program that creates a file containing two 4 | # user-provided strings,one per line. 5 | # 6 | # Author -> Billy Murphy 12 April 2022 7 | 8 | 9 | #This is the first prompt asking for the name of the text file 10 | file_name = input('What would you like to name your text file: ') 11 | 12 | #This line creates a file using the given file name and allows the program to write to it. 13 | fname = open(str(file_name), "w") 14 | 15 | #These next four lines of code prompt the user for the two strings 16 | print('What is the first string?') 17 | str_1 = input() 18 | 19 | print('What is the second string?') 20 | str_2 = input() 21 | 22 | #The two strings are then saved into a list with 2 entries 23 | #string one plus a new line character, 24 | #and string two, with another new line character 25 | L = [str(str_1)+'\n', str(str_2)+'\n'] 26 | 27 | #This line writes the list of string, list L, to the text file 28 | fname.writelines(L) 29 | 30 | #In order to let the user confirm that the program ran properly. 31 | #A print statement is given confirming 32 | print('The text file '+str(file_name)+' is now in your current working directory') 33 | 34 | #This line closes the file 35 | fname.close() 36 | 37 | -------------------------------------------------------------------------------- /ds_algos/1d_dynamic/climbingStairs.py: -------------------------------------------------------------------------------- 1 | # memoization and caching or true dynamic solution -> NOPE 2 | # bottom up dynamic programming solution -> Oh Ya!! 3 | 4 | 5 | def climbStairs(n): 6 | one, two = 1, 1 7 | 8 | for i in range(n - 1): 9 | temp = one 10 | one = one + two 11 | two = temp 12 | 13 | return one 14 | 15 | 16 | print(climbStairs(5)) 17 | -------------------------------------------------------------------------------- /ds_algos/1d_dynamic/fibonacci.py: -------------------------------------------------------------------------------- 1 | # compute the fibonacci number 2 | 3 | # The input will be the index n of the fibonacci series 4 | # and the output should be F(n) 5 | 6 | 7 | # This is a dynamic programming solution that utilizes the 8 | # the bottom up approach for a linear problem 9 | # The space compexity is O(1) and time complexity is O(n) 10 | def F(n): 11 | # This is the "cache" that will hold 12 | # previously computed values 13 | results = [0, 1] 14 | # These two conditionals handle the 15 | # edge cases 16 | if n <= 0: 17 | return 0 18 | if n == 1: 19 | return 1 20 | # Inititalizing a counter variable to 21 | i = 1 22 | while i < n: 23 | # iteratively find the sum of our 24 | # results arr 25 | sum = results[0] + results[1] 26 | # and update the results array 27 | # to hold the prvious el at arr[1] and 28 | # the newly computed sum 29 | results = [results[1], sum] 30 | # then incrementing i 31 | i += 1 32 | # return the last sum => F(n) 33 | return sum 34 | 35 | 36 | print(F(5)) # 0, 1, 1, 2 , 3 37 | -------------------------------------------------------------------------------- /ds_algos/2d_dynamic/knapsack.py: -------------------------------------------------------------------------------- 1 | # 0/1 Knapsack 2 | # 2-d dynamic programming problem (take it or leave it!!!) 3 | 4 | # can the target be reached with the given arr 5 | 6 | # input: [1,2,3] target = 5 7 | 8 | 9 | def knapSack(arr, target): 10 | return True 11 | -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/containsDup.py: -------------------------------------------------------------------------------- 1 | # Given an integer array nums, 2 | # return true if any value appears at least twice in the array, 3 | # and return false if every element is distinct. 4 | 5 | def containsDuplicate(nums): 6 | """ 7 | :type nums: List[int] 8 | :rtype: bool 9 | """ 10 | dict = {} 11 | for el in nums: 12 | if el not in dict: 13 | dict[el] = el 14 | else: 15 | return True 16 | return False 17 | 18 | 19 | # PASSES 20 | 21 | # nums = [1,2,3,4,5] 22 | 23 | # print(containsDuplicate(nums)) -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/groupAnagrams.py: -------------------------------------------------------------------------------- 1 | # Input: strs = ["eat","tea","tan","ate","nat","bat"] 2 | # Output: [["bat"],["nat","tan"],["ate","eat","tea"]] 3 | 4 | 5 | from typing import List 6 | import collections 7 | 8 | 9 | class Solution: 10 | def groupAnagrams(self, strs: List[str]) -> List[List[str]]: 11 | ans = collections.defaultdict(list) 12 | 13 | for s in strs: 14 | count = [0] * 26 15 | for c in s: 16 | count[ord(c) - ord("a")] += 1 17 | ans[tuple(count)].append(s) 18 | return ans.values() 19 | 20 | 21 | def groupAnagrams(strs: List[str]) -> List[List[str]]: 22 | ans = collections.defaultdict(list) 23 | 24 | for s in strs: 25 | # creating a list of 26 zeros 26 | count = [0] * 26 27 | for c in s: 28 | # counting the number of occurrences of each letter in a string, 29 | # using the ASCII value of the letters to determine their index in the count list 30 | count[ord(c) - ord("a")] += 1 31 | # this line is grouping the strings by their character counts. 32 | # All the anagrams have the same counts and hence end up in the 33 | # same list in the dictionary 34 | ans[tuple(count)].append(s) 35 | return list(ans.values()) 36 | 37 | 38 | print( 39 | groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]) 40 | ) # -> dict_values([['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]) 41 | 42 | 43 | # NOTE more detail: 44 | # ord(c): This is a built-in function in Python that returns an 45 | # integer representing the Unicode character. 46 | # 47 | # For example, ord('a') will return 97 48 | -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/twoSum.py: -------------------------------------------------------------------------------- 1 | # Given an array of integers nums and an integer target, 2 | # return indices of the two numbers such that they add up to target. 3 | 4 | # You may assume that each input would have exactly one solution, 5 | # and you may not use the same element twice. 6 | 7 | # You can return the answer in any order. 8 | 9 | class Solution(object): 10 | def twoSum(self, nums, target): 11 | """ 12 | :type nums: List[int] 13 | :type target: int 14 | :rtype: List[int] 15 | """ 16 | dict = {} 17 | for i in range(len(nums)): 18 | el = nums[i] 19 | comp = target - el 20 | if comp in dict: 21 | return dict[comp], i 22 | else: 23 | dict[el] = i 24 | return 25 | 26 | nums = [-3,4,3,90] 27 | solution = Solution() 28 | print(solution.twoSum(nums, 0)) -------------------------------------------------------------------------------- /ds_algos/arrays_hashTables/validAnagram.py: -------------------------------------------------------------------------------- 1 | # Given two strings s and t, return true if t is an anagram of s, and false otherwise. 2 | 3 | 4 | def isAnagram(s: str, t: str) -> bool: 5 | if len(s) != len(t): 6 | return False 7 | 8 | countS, countT = {}, {} 9 | 10 | for i in range(len(s)): 11 | countS[s[i]] = 1 + countS.get(s[i], 0) 12 | countT[t[i]] = 1 + countT.get(t[i], 0) 13 | return countS == countT 14 | 15 | class Solution2(object): 16 | def isAnagram(self, s, t): 17 | """ 18 | :type s: str 19 | :type t: str 20 | :rtype: bool 21 | """ 22 | if len(s) != len(t): 23 | return False 24 | return sorted(s) == sorted(t) 25 | 26 | s = "accc" 27 | t = "aacc" 28 | 29 | print(isAnagram(s,t)) -------------------------------------------------------------------------------- /ds_algos/backTracking copy/nQueens.py: -------------------------------------------------------------------------------- 1 | # N-queens 2 | 3 | # we are given n queens and n differnet queens, such that no two queens never attack each other 4 | 5 | # example 6 | # [[0,1,0,0], 7 | # [0,0,0,1], 8 | # [1,0,0,0], 9 | # [0,0,1,0]] 10 | 11 | # every queen has to be in a different row and column 12 | # (the hard part is diagonals) Each queen can only be in 13 | # different diagonals 14 | 15 | def nQueens(n): 16 | col = set() 17 | posDiag = set() # (r + c) 18 | negDiag = set() # (r - c) 19 | 20 | # list of solutions 21 | res = [] 22 | # Board that we are traversing 23 | board = [["."] * n for i in range(n)] 24 | 25 | # backtracking function 26 | def backTrack(r): 27 | # we've found a solution 28 | if r == n: 29 | copy = ["".join(row) for row in board] 30 | res.append(copy) 31 | return 32 | 33 | # Backtrack baby! 34 | for c in range(n): 35 | # check for error conditions 36 | if c in col or (r + c) in posDiag or (r - c) in negDiag: 37 | continue 38 | # if passed error conditions 39 | # add the next set of error conditions for next back track 40 | col.add(c) 41 | posDiag.add(r + c) 42 | negDiag.add(r - c) 43 | board[r][c] = "Q" 44 | 45 | # recursive case 46 | backTrack(r + 1) 47 | 48 | # remove the last error conditions (and queen) 49 | col.remove(c) 50 | posDiag.remove(r + c) 51 | negDiag.remove(r - c) 52 | board[r][c] = "." 53 | 54 | # start backtracking 55 | backTrack(0) 56 | return res 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking copy/wordSearch.py: -------------------------------------------------------------------------------- 1 | # Given an NxN board of letters and a string 2 | # return true or false if the word can be 3 | # constructed by only moving horizontally or 4 | # vertically within the board 5 | 6 | board = [ 7 | ["a", "b", "c", "d"], 8 | ["e", "f", "h", "i"], 9 | ["j", "k", "l", "m"], 10 | ["n", "o", "p", "q"], 11 | ["r", "s", "t", "u"], 12 | ] 13 | 14 | 15 | def wordSearch(board, word): 16 | rows, cols = len(board), len(board[0]) 17 | # this will hold onto the previously visited node 18 | path = set() 19 | 20 | # // backtracking for depth first search 21 | def dfs(r, c, i): 22 | # base case 23 | if i == len(word): 24 | return True 25 | # boundry of false conditions 26 | if ( 27 | r < 0 28 | or r >= rows 29 | or c < 0 30 | or c >= cols 31 | or board[r][c] != word[i] 32 | or (r, c) in path 33 | ): 34 | return False 35 | 36 | path.add((r, c)) 37 | res = ( 38 | dfs(r + 1, c, i + 1) 39 | or dfs(r - 1, c, i + 1) 40 | or dfs(r, c + 1, i + 1) 41 | or dfs(r, c - 1, i + 1) 42 | ) 43 | 44 | path.remove((r, c)) 45 | return res 46 | 47 | for i in range(rows): 48 | for j in range(cols): 49 | if dfs(i, j, 0): 50 | return True 51 | 52 | return False 53 | 54 | # O(n * m * 4^n) 55 | 56 | print(wordSearch(board, "abc")) 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking/nQueens.py: -------------------------------------------------------------------------------- 1 | # N-queens 2 | 3 | # we are given n queens and n differnet queens, such that no two queens never attack each other 4 | 5 | # example 6 | # [[0,1,0,0], 7 | # [0,0,0,1], 8 | # [1,0,0,0], 9 | # [0,0,1,0]] 10 | 11 | # every queen has to be in a different row and column 12 | # (the hard part is diagonals) Each queen can only be in 13 | # different diagonals 14 | 15 | def nQueens(n): 16 | col = set() 17 | posDiag = set() # (r + c) 18 | negDiag = set() # (r - c) 19 | 20 | # list of solutions 21 | res = [] 22 | # Board that we are traversing 23 | board = [["."] * n for i in range(n)] 24 | 25 | # backtracking function 26 | def backTrack(r): 27 | # we've found a solution 28 | if r == n: 29 | copy = ["".join(row) for row in board] 30 | res.append(copy) 31 | return 32 | 33 | # Backtrack baby! 34 | for c in range(n): 35 | # check for error conditions 36 | if c in col or (r + c) in posDiag or (r - c) in negDiag: 37 | continue 38 | # if passed error conditions 39 | # add the next set of error conditions for next back track 40 | col.add(c) 41 | posDiag.add(r + c) 42 | negDiag.add(r - c) 43 | board[r][c] = "Q" 44 | 45 | # recursive case 46 | backTrack(r + 1) 47 | 48 | # remove the last error conditions (and queen) 49 | col.remove(c) 50 | posDiag.remove(r + c) 51 | negDiag.remove(r - c) 52 | board[r][c] = "." 53 | 54 | # start backtracking 55 | backTrack(0) 56 | return res 57 | -------------------------------------------------------------------------------- /ds_algos/backTracking/wordSearch.py: -------------------------------------------------------------------------------- 1 | # Given an NxN board of letters and a string 2 | # return true or false if the word can be 3 | # constructed by only moving horizontally or 4 | # vertically within the board 5 | 6 | board = [ 7 | ["a", "b", "c", "d"], 8 | ["e", "f", "h", "i"], 9 | ["j", "k", "l", "m"], 10 | ["n", "o", "p", "q"], 11 | ["r", "s", "t", "u"], 12 | ] 13 | 14 | 15 | def wordSearch(board, word): 16 | rows, cols = len(board), len(board[0]) 17 | # this will hold onto the previously visited node 18 | path = set() 19 | 20 | # // backtracking for depth first search 21 | def dfs(r, c, i): 22 | # base case 23 | if i == len(word): 24 | return True 25 | # boundry of false conditions 26 | if ( 27 | r < 0 28 | or r >= rows 29 | or c < 0 30 | or c >= cols 31 | or board[r][c] != word[i] 32 | or (r, c) in path 33 | ): 34 | return False 35 | 36 | path.add((r, c)) 37 | res = ( 38 | dfs(r + 1, c, i + 1) 39 | or dfs(r - 1, c, i + 1) 40 | or dfs(r, c + 1, i + 1) 41 | or dfs(r, c - 1, i + 1) 42 | ) 43 | 44 | path.remove((r, c)) 45 | return res 46 | 47 | for i in range(rows): 48 | for j in range(cols): 49 | if dfs(i, j, 0): 50 | return True 51 | 52 | return False 53 | 54 | # O(n * m * 4^n) 55 | 56 | print(wordSearch(board, "abc")) 57 | -------------------------------------------------------------------------------- /ds_algos/fastAndSlow.py: -------------------------------------------------------------------------------- 1 | # Q: find the middle of a linkedList 2 | 3 | # fast point is shifted by 2 (always?) 4 | # slow point is incremented by 1 (always?) 5 | 6 | def middleOfList(head): 7 | slow, fast = head, head 8 | while fast and fast.next: 9 | slow = slow.next 10 | fast = fast.next.next 11 | return slow 12 | 13 | # O(n) space complexity 14 | # fn hasCycle(head): 15 | # visited = set() 16 | # while head is not null: 17 | # if head in visited: 18 | # return true 19 | # head = head.next 20 | # return false 21 | 22 | # O(1) space complexity 23 | # what if the LL has a cycle in it? 24 | def cycleDetection(head): 25 | slow, fast = head, head 26 | while fast and fast.next: 27 | slow = slow.next 28 | fast = fast.next.next 29 | if slow == fast: 30 | return True 31 | return False 32 | 33 | 34 | # Where does the cycle start? 35 | def cycleStart(head): 36 | slow, fast = head, head 37 | while fast and fast.next: 38 | slow = slow.next 39 | fast = fast.next.next 40 | 41 | if slow == fast: 42 | break 43 | 44 | if not fast or not fast.next: 45 | return None 46 | 47 | slow2 = head 48 | while slow != slow2: 49 | slow = slow.next 50 | slow2 = slow2.next 51 | 52 | return slow 53 | 54 | # Mathematical Proof of Floyd's Tortoise and Hare 55 | 56 | # 1. Let the distance between the head node and the node at which the cycle starts be denoted by P 57 | 58 | # 2. Let the length of the cycle be denoted by C 59 | 60 | # 3. Let the distance from the node at which slow and fast 61 | # intersect to the node at which the cycle begins, be denoted by X 62 | 63 | # Using this information, we can derive that the distance between the head node and the node at which fast and slow intersect is C − X 64 | 65 | # We know that 2∗slow = fast. Using the information above, let's rewrite this equation in terms of the 66 | # C,X,P, we get the following. -------------------------------------------------------------------------------- /ds_algos/graphs/graphGraphs/graphIntro.py: -------------------------------------------------------------------------------- 1 | # 1 Matrix 2 | # 2 Adjacency Matrix 3 | # 3 Adjacent List 4 | # 5 | # NOTE: 6 | # Vertices are the same as nodes 7 | # Pointers are Edges 8 | 9 | # Graphs can, and often do, have cycles! 10 | # Edges <= (Vertices)^2 11 | 12 | # Directed Graph -> Each pointer has a direction (BST and singlely-LL are directed graphs) 13 | 14 | # Undirected Graphs are essentially doubly-LL 15 | 16 | # Matrix (undirected graph) 17 | 18 | treasureMap = [[0, 0, 0, 0], 19 | [1, 1, 'X', 0], 20 | [1, 0, 0, 1], 21 | [0, 0, 1, 0]] 22 | 23 | teasure = treasureMap[1][2] # row 1 and column 2 24 | 25 | # Adjecency matrix 26 | grid = [[0, 0, 0, 0], 27 | [1, 1, 0, 0], 28 | [1, 0, 0, 1], 29 | [0, 0, 1, 0]] 30 | 31 | 32 | def dfs(grid, r, c, visit = set()): 33 | ROWS, COLS = len(grid), len(grid[0]) 34 | if (min(r,c) < 0 or 35 | r == ROWS or c == COLS or 36 | (r, c) in visit or grid[r][c] == 1): 37 | return 0 38 | if r == ROWS - 1 or c == COLS - 1: 39 | return 1 40 | 41 | count = 0 42 | visit.add((r, c)) 43 | count += dfs(grid, r + 1, c, visit) 44 | count += dfs(grid, r - 1, c, visit) 45 | count += dfs(grid, r, c + 1, visit) 46 | count += dfs(grid, r, c - 1, visit) 47 | 48 | visit.remove((r, c)) 49 | return count 50 | 51 | print(dfs(grid, 0, 0, set())) -------------------------------------------------------------------------------- /ds_algos/graphs/tree/trie.py: -------------------------------------------------------------------------------- 1 | # This is for finding prefix tree. This helps with auto complete 2 | 3 | # It is a node of characters ( a - z ) and every node 4 | 5 | class TrieNode: 6 | def __init__(self): 7 | self.children = {} 8 | self.word = False # Mark the end of a work (this indicate it's not the end) 9 | 10 | class Trie: 11 | def __init__(self): 12 | self.root = TrieNode() 13 | 14 | 15 | def insert(self, word): 16 | curr = self.root 17 | # Go through every character in 'word' 18 | for c in word: 19 | # If the letter is not a child of the current character 20 | if c not in curr.children: 21 | # Insert a new node 22 | curr.children[c] = TrieNode() 23 | curr = curr.children[c] 24 | curr.word = True # Mark the end of a work (this indicate it is the end) 25 | 26 | def search(self, word): 27 | curr = self.root 28 | for c in word: 29 | if c not in curr.children: 30 | return False 31 | curr = curr.children[c] 32 | return curr.word 33 | 34 | # Main use case of this data structure 35 | def startsWith(self, prefix): 36 | curr = self.root 37 | for c in prefix: 38 | if c not in curr.children: 39 | return False 40 | curr = curr.children[c] 41 | return True -------------------------------------------------------------------------------- /ds_algos/prefixSum/prefixSum.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Prefix Sum -> Starting at the beginning.... ? 5 | 6 | # nums = [2, -1, 3, -3, 4] ( any prefex is [2], [2, -1], [2, -1, 3],...) 7 | # a post fix if the same but from the end 8 | 9 | def prefixSum(nums): 10 | preSum = 0 11 | 12 | for el in nums: 13 | preSum += el 14 | return preSum 15 | 16 | def postFix(nums): 17 | postSum = 0 18 | 19 | for el in reversed(nums): 20 | postSum += el 21 | return postSum 22 | 23 | # Q Given an array of values, design a data structure that can query the sum 24 | # of a subarray of the values 25 | 26 | class PrefixSum: 27 | 28 | def __init__(self, nums): 29 | self.prefix = [] #an array of totals prefixes 30 | total = 0 31 | for n in nums: 32 | total += n 33 | self.prefix.append(total) 34 | 35 | def rangeSum(self, left, right): #Assuming range sum is called much more frequently 36 | preRight = self.prefix[right] 37 | preLeft = self.prefix[left - 1] if left > 0 else 0 # Edge case for L = 0 38 | return (preRight - preLeft) 39 | 40 | # This allows you to add to the PrefixSum class in O(1) time complexity 41 | def addElement(self, element): 42 | newLastElement = element + self.prefix[-1] 43 | self.prefix.append(newLastElement) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ds_algos/savingaFile.js: -------------------------------------------------------------------------------- 1 | const twoSumClosest = (nums, target) => { 2 | // O(nlogn) 3 | const sorted = nums.sort((a, b) => a - b) 4 | // initialize the two pointers 5 | 6 | let l = 0; 7 | let r = sorted.length - 1; 8 | let min = Infinity; 9 | 10 | // while left pointer is less than right pointer (l and r meet in the middle) 11 | while (l <= r) { 12 | // initialize a sum to left and right elements 13 | const sum = sorted[l] + sorted[r]; 14 | // initialize a measure of the distance between our sum and target 15 | // NOTE - the sign is super important for how we move our pointers 16 | const distance = target - sum 17 | // the return condition 18 | if (Math.abs(distance) < min && Math.abs(distance) >= 0) { // <-- Is distance between 0 and min? 19 | // If it is, reassign min and closestSum 20 | min = Math.abs(distance) 21 | closestSum = sum 22 | // Additionally, if the min is 0, return closestSum immediately 23 | if (min === 0) return closestSum; 24 | } 25 | // If sum is less that target, increase left 26 | if (distance > 0) { 27 | l++; 28 | // else decrease right! 29 | } else { 30 | r--; 31 | } 32 | } 33 | return closestSum 34 | }; 35 | 36 | // console.log(twoSumClosest([2,-2,1], 4)) 37 | // console.log(twoSumClosest([2, -3, -6, 7, 4], 3)) 38 | console.log(twoSumClosest([3, 1, 4, 3], 6)) 39 | 40 | module.exports = {twoSumClosest}; -------------------------------------------------------------------------------- /ds_algos/stacks/kFrequentEl.py: -------------------------------------------------------------------------------- 1 | # Given an integer array nums and an integer k, return the k most frequent elements. 2 | # You may return the answer in any order. 3 | 4 | # Input: nums = [1,1,1,2,2,3], k = 2 5 | # Output: [1,2] 6 | 7 | def topKFrequent(nums, k): 8 | """ 9 | :type nums: List[int] 10 | :type k: int 11 | :rtype: List[int] 12 | """ 13 | dict = {} 14 | for el in nums: 15 | if el in dict: 16 | dict[el] += 1 17 | if el not in dict: 18 | dict[el] = 1 19 | 20 | resultArr = sorted(dict, key=dict.get, reverse=True) 21 | return resultArr[0:k] 22 | 23 | print(topKFrequent([1,1,1,2,2,3,3,3,3,3], 2)) 24 | 25 | 26 | # Almost done, but just having trouble with syntax -------------------------------------------------------------------------------- /ds_algos/stacks/validParens.py: -------------------------------------------------------------------------------- 1 | # Write a function that takes in a string and returns a 'True' 2 | # if the parentheses are balances or 'False' if they are not 3 | 4 | # Input: s = "()[]{}" 5 | # Output: True 6 | 7 | 8 | def validParens(str): 9 | dict = {"[": "]", "{": "}", "(": ")"} 10 | stack = [] 11 | 12 | for char in str: 13 | if char in dict: 14 | stack.append(char) 15 | elif stack and char == dict[stack[-1]]: 16 | stack.pop() 17 | else: 18 | return False 19 | 20 | return len(stack) == 0 21 | 22 | 23 | print(validParens("[{[()]}]()")) 24 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/kadanes_algo.py: -------------------------------------------------------------------------------- 1 | #Find a non-empty subarray with the largest sum 2 | 3 | #Kadane's Algorith is O(n) 4 | 5 | #There is a sliding window that is non obvious 6 | 7 | 8 | # def kadanes(nums): 9 | # maxSum = nums[0] 10 | # curSum = 0 11 | 12 | # for n in nums: 13 | # # Ensuring that our current sum is never negative 14 | # curSum = max(curSum, 0) 15 | # curSum += n 16 | # maxSum = max(maxSum, curSum) 17 | # return maxSum 18 | 19 | def kadanes(nums): 20 | maxSum = nums[0] 21 | curSum = 0 22 | 23 | for n in nums: 24 | curSum = max(curSum, 0) + n 25 | maxSum = max(maxSum, curSum) 26 | 27 | return maxSum 28 | 29 | #How do you return the actual subarray? 30 | # You need to keep track of the indexes of the subarray 31 | 32 | 33 | def slidingWindow(nums): 34 | maxSum = nums[0] 35 | curSum = 0 36 | 37 | # Set the indexes 38 | maxL, maxR = 0, 0 39 | L = 0 40 | 41 | # R will change and L will be reassigned 42 | for R in range(len(nums)): 43 | # The first line of the kadanes for loop 44 | # We've found a window that sums to a negative number 45 | if curSum < 0: 46 | curSum = 0 47 | L = R 48 | 49 | # The second line of kadanes for loops 50 | curSum += nums[R] 51 | if curSum > maxSum: 52 | maxSum = curSum 53 | maxL, maxR = L , R 54 | 55 | # Return the subArray defined by maxL and maxR 56 | return nums[maxL:maxR] 57 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/slidingWindow.py: -------------------------------------------------------------------------------- 1 | # Given an array, return true if there 2 | # are two elements within a window of size k that are equal 3 | 4 | def closeDuplicates(nums, k): 5 | # Initialize a HastSet and L pointer 6 | window = set() 7 | L = 0 8 | 9 | # Iterate through the array 10 | for R in range(len(nums)): 11 | # If the two points extend past the window 12 | if R - L + 1 > k: 13 | # Remove the left element and resize the window 14 | window.remove(nums[L]) 15 | L += 1 16 | # If there is an element inside the HashSet 17 | if nums[R] in window: 18 | return True 19 | # Else add the element to the hashSet 20 | window.add(nums[R]) 21 | 22 | # Once we get the end of the array, w/o returning True... 23 | return False -------------------------------------------------------------------------------- /ds_algos/twoPointer/targetSum.py: -------------------------------------------------------------------------------- 1 | # Q: Given a sorted input array, return the two indices of two elements which 2 | # sums up to the target value. Assume there's exactly one solution. 3 | 4 | def targetSum(nums, target): 5 | L, curSum = 0, 0 6 | R = len(nums) - 1 7 | 8 | while R > L: 9 | curSum = nums[R] + nums[L] 10 | if curSum > target: 11 | R -= 1 12 | elif curSum < target: 13 | L += 1 14 | elif curSum == target: 15 | return [L, R] 16 | return -1 # Not needed since there is always a solution, but generalizes the code 17 | 18 | nums = [-1,2,4,6,9,10,12] 19 | target = 1 20 | 21 | print(targetSum(nums, target)) -------------------------------------------------------------------------------- /ds_algos/twoPointer/validPalindrome.py: -------------------------------------------------------------------------------- 1 | # Write a function that takes in 2 | # a string and returns a boolean; 3 | # 'True" if the string is a valid palindrome 4 | # and 'False' if it is not 5 | 6 | 7 | def validPalindrom(str): 8 | l, r = 0, len(str) - 1 9 | 10 | while l <= r: 11 | if str[l] != str[r]: 12 | return False 13 | else: 14 | l += 1 15 | r -= 1 16 | 17 | return True 18 | 19 | 20 | print(validPalindrom("racecar")) # -> True 21 | print(validPalindrom("notTrue")) # -> False 22 | -------------------------------------------------------------------------------- /ds_algos/twoPointer/varyingSlidingWindow.py: -------------------------------------------------------------------------------- 1 | # Q: Find the length of the longest subarray, 2 | # with the same value in each position 3 | 4 | def longestSubarray(nums): 5 | length = 0 6 | L = 0 7 | 8 | for R in range(len(nums)): 9 | if nums[L] != nums[R]: 10 | L = R 11 | length = max(length, R - L + 1) 12 | return length 13 | 14 | # How do you write the array above without L and R pointers 15 | 16 | # Q: Find the length subarray, where the sum is greater that or equal to the target. 17 | # Assume all the values are positive (Important note/ hint!!) 18 | 19 | # O(n) time complexity and O(1) space complexity 20 | 21 | def shortestSubarry(nums, target): 22 | L, total = 0, 0 23 | length = float('inf') 24 | 25 | # Move R pointer right 26 | for R in range(len(nums)): # EXPAND THE WINDOW 27 | # wioth every step, add the elemenet to the total 28 | total += nums[R] 29 | # IF the total is greater than OR equal to the target 30 | while total >= target: # SHRINK THE WINDOW 31 | # possibly re-assign the length 32 | length = min(R - L + 1, length) 33 | # decrement the total by L pointer elements 34 | # until the total < target 35 | total -+ nums[L] 36 | L += 1 37 | # return o if length i infinite else return length 38 | return 0 if length == float('inf') else length 39 | -------------------------------------------------------------------------------- /fft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # fft.py - Demonstrate power spectrum from discrete fft 5 | # 6 | # 25Jul22 William Murphy 7 | # 8 | 9 | FTIME = 1 # function range in seconds 10 | FS = 920 # samples per second 11 | npts = FTIME*FS # number of sample points 12 | 13 | import numpy as np 14 | import matplotlib.pyplot as plt 15 | 16 | #solar cell data into numpy array 17 | sc_data = np.loadtxt('fft_data.txt') 18 | 19 | #print(sc_data) 20 | 21 | #plots the raw data 22 | t = np.linspace(0, FTIME, npts) 23 | y_raw = sc_data 24 | y_fft = sc_data - np.mean(sc_data) 25 | f1, ax1 = plt.subplots() 26 | ax1.plot(t,y_raw) 27 | ax1.set_title('Data Acquisition of Solar Cell') 28 | ax1.set_xlabel('Sec') 29 | ax1.set_ylabel('Voltage') 30 | f1.show() 31 | 32 | #Computng the FFT 33 | ft = np.fft.fft(y_fft, n=16*npts) 34 | ftnorm = abs(ft) 35 | fs = ftnorm**2 36 | ps = np.fft.fftshift(fs) 37 | x_vals = np.fft.fftfreq(len(ps), 1.0/FS) 38 | xvals = np.fft.fftshift(x_vals) 39 | 40 | f2, ax2 = plt.subplots() 41 | ax2.plot(xvals,ps) 42 | ax2.set_xlim(0,200) 43 | ax2.title.set_text('FFT of Raw Data') 44 | ax2.set_xlabel('Frequency') 45 | ax2.set_ylabel('Amplitude') 46 | f2.show() 47 | 48 | input('\nPress to exit...\n') 49 | -------------------------------------------------------------------------------- /fft_data.txt: -------------------------------------------------------------------------------- 1 | 2.440074465163121431e+00 2 | 2.476075563829462478e+00 3 | 2.476075563829462478e+00 4 | 2.438074404126102657e+00 5 | 2.380072634052552871e+00 6 | 2.342071474349193050e+00 7 | 2.360072023682363351e+00 8 | 2.414073671681875144e+00 9 | 2.464075197607348944e+00 10 | 2.482075746940519689e+00 11 | 2.460075075533310951e+00 12 | 2.406073427533799602e+00 13 | 2.352071779534287366e+00 14 | 2.346071596423230599e+00 15 | 2.390072939237647631e+00 16 | 2.446074648274178642e+00 17 | 2.478075624866481697e+00 18 | 2.472075441755424485e+00 19 | 2.432074221015045445e+00 20 | 2.372072389904476886e+00 21 | 2.342071474349193050e+00 22 | 2.366072206793420118e+00 23 | 2.422073915829951130e+00 24 | 2.468075319681386937e+00 25 | 2.480075685903500471e+00 26 | 2.454074892422254184e+00 27 | 2.396073122348704398e+00 28 | 2.348071657460249373e+00 29 | 2.348071657460249373e+00 30 | 2.396073122348704398e+00 31 | 2.452074831385234965e+00 32 | 2.480075685903500471e+00 33 | 2.470075380718405711e+00 34 | 2.424073976866969904e+00 35 | 2.424073976866969904e+00 36 | 2.364072145756401344e+00 37 | 2.340071413312173831e+00 38 | 2.430074159978026671e+00 39 | 2.472075441755424485e+00 40 | 2.472075441755424485e+00 41 | 2.478075624866481697e+00 42 | 2.446074648274178642e+00 43 | 2.388072878200628413e+00 44 | 2.344071535386211380e+00 45 | 2.352071779534287366e+00 46 | 2.404073366496780384e+00 47 | 2.456074953459272958e+00 48 | 2.480075685903500471e+00 49 | 2.464075197607348944e+00 50 | 2.414073671681875144e+00 51 | 2.358071962645344577e+00 52 | 2.342071474349193050e+00 53 | 2.378072573015534097e+00 54 | 2.436074343089083438e+00 55 | 2.474075502792443704e+00 56 | 2.476075563829462478e+00 57 | 2.440074465163121431e+00 58 | 2.380072634052552871e+00 59 | 2.340071413312173831e+00 60 | 2.356071901608325359e+00 61 | 2.410073549607837151e+00 62 | 2.462075136570330169e+00 63 | 2.480075685903500471e+00 64 | 2.458075014496292177e+00 65 | 2.406073427533799602e+00 66 | 2.352071779534287366e+00 67 | 2.342071474349193050e+00 68 | 2.384072756126590864e+00 69 | 2.442074526200140649e+00 70 | 2.476075563829462478e+00 71 | 2.472075441755424485e+00 72 | 2.432074221015045445e+00 73 | 2.432074221015045445e+00 74 | 2.370072328867458111e+00 75 | 2.338071352275155057e+00 76 | 2.362072084719382570e+00 77 | 2.418073793755913137e+00 78 | 2.464075197607348944e+00 79 | 2.478075624866481697e+00 80 | 2.452074831385234965e+00 81 | 2.396073122348704398e+00 82 | 2.344071535386211380e+00 83 | 2.344071535386211380e+00 84 | 2.390072939237647631e+00 85 | 2.446074648274178642e+00 86 | 2.476075563829462478e+00 87 | 2.466075258644368162e+00 88 | 2.422073915829951130e+00 89 | 2.362072084719382570e+00 90 | 2.336071291238135839e+00 91 | 2.364072145756401344e+00 92 | 2.422073915829951130e+00 93 | 2.466075258644368162e+00 94 | 2.474075502792443704e+00 95 | 2.444074587237159424e+00 96 | 2.384072756126590864e+00 97 | 2.338071352275155057e+00 98 | 2.344071535386211380e+00 99 | 2.394073061311685624e+00 100 | 2.448074709311197417e+00 101 | 2.474075502792443704e+00 102 | 2.458075014496292177e+00 103 | 2.410073549607837151e+00 104 | 2.352071779534287366e+00 105 | 2.332071169164097846e+00 106 | 2.368072267830438893e+00 107 | 2.426074037903989122e+00 108 | 2.464075197607348944e+00 109 | 2.466075258644368162e+00 110 | 2.432074221015045445e+00 111 | 2.432074221015045445e+00 112 | 2.372072389904476886e+00 113 | 2.330071108127079071e+00 114 | 2.344071535386211380e+00 115 | 2.398073183385723617e+00 116 | 2.448074709311197417e+00 117 | 2.468075319681386937e+00 118 | 2.448074709311197417e+00 119 | 2.396073122348704398e+00 120 | 2.340071413312173831e+00 121 | 2.328071047090059853e+00 122 | 2.368072267830438893e+00 123 | 2.426074037903989122e+00 124 | 2.460075075533310951e+00 125 | 2.458075014496292177e+00 126 | 2.418073793755913137e+00 127 | 2.356071901608325359e+00 128 | 2.320070802941984311e+00 129 | 2.342071474349193050e+00 130 | 2.396073122348704398e+00 131 | 2.446074648274178642e+00 132 | 2.460075075533310951e+00 133 | 2.434074282052064664e+00 134 | 2.378072573015534097e+00 135 | 2.324070925016021860e+00 136 | 2.320070802941984311e+00 137 | 2.366072206793420118e+00 138 | 2.422073915829951130e+00 139 | 2.452074831385234965e+00 140 | 2.444074587237159424e+00 141 | 2.398073183385723617e+00 142 | 2.338071352275155057e+00 143 | 2.338071352275155057e+00 144 | 2.308070436719870333e+00 145 | 2.334071230201117064e+00 146 | 2.392073000274666406e+00 147 | 2.436074343089083438e+00 148 | 2.444074587237159424e+00 149 | 2.414073671681875144e+00 150 | 2.354071840571306584e+00 151 | 2.306070375682851559e+00 152 | 2.308070436719870333e+00 153 | 2.358071962645344577e+00 154 | 2.412073610644855925e+00 155 | 2.438074404126102657e+00 156 | 2.424073976866969904e+00 157 | 2.374072450941496104e+00 158 | 2.312070558793908326e+00 159 | 2.290069887386700032e+00 160 | 2.322070863979003530e+00 161 | 2.380072634052552871e+00 162 | 2.422073915829951130e+00 163 | 2.424073976866969904e+00 164 | 2.390072939237647631e+00 165 | 2.328071047090059853e+00 166 | 2.282069643238624046e+00 167 | 2.292069948423719250e+00 168 | 2.344071535386211380e+00 169 | 2.398073183385723617e+00 170 | 2.418073793755913137e+00 171 | 2.398073183385723617e+00 172 | 2.344071535386211380e+00 173 | 2.284069704275643264e+00 174 | 2.268069215979491737e+00 175 | 2.308070436719870333e+00 176 | 2.366072206793420118e+00 177 | 2.404073366496780384e+00 178 | 2.402073305459761610e+00 179 | 2.402073305459761610e+00 180 | 2.362072084719382570e+00 181 | 2.298070131534776017e+00 182 | 2.258068910794396977e+00 183 | 2.274069399090548504e+00 184 | 2.330071108127079071e+00 185 | 2.382072695089572090e+00 186 | 2.398073183385723617e+00 187 | 2.374072450941496104e+00 188 | 2.316070680867946319e+00 189 | 2.258068910794396977e+00 190 | 2.250068666646320992e+00 191 | 2.294070009460738024e+00 192 | 2.354071840571306584e+00 193 | 2.386072817163609638e+00 194 | 2.380072634052552871e+00 195 | 2.334071230201117064e+00 196 | 2.270069277016510512e+00 197 | 2.236068239387188683e+00 198 | 2.260068971831416196e+00 199 | 2.316070680867946319e+00 200 | 2.364072145756401344e+00 201 | 2.372072389904476886e+00 202 | 2.342071474349193050e+00 203 | 2.280069582201605716e+00 204 | 2.226067934202093479e+00 205 | 2.222067812128055486e+00 206 | 2.268069215979491737e+00 207 | 2.320070802941984311e+00 208 | 2.346071596423230599e+00 209 | 2.330071108127079071e+00 210 | 2.276069460127567723e+00 211 | 2.210067445905941952e+00 212 | 2.210067445905941952e+00 213 | 2.176066408276620123e+00 214 | 2.200067140720847192e+00 215 | 2.252068727683340210e+00 216 | 2.288069826349681257e+00 217 | 2.288069826349681257e+00 218 | 2.248068605609302217e+00 219 | 2.180066530350657672e+00 220 | 2.126064882351145879e+00 221 | 2.122064760277107887e+00 222 | 2.162065981017486926e+00 223 | 2.210067445905941952e+00 224 | 2.226067934202093479e+00 225 | 2.204067262794885185e+00 226 | 2.146065492721335399e+00 227 | 2.078063417462690854e+00 228 | 2.048062501907407018e+00 229 | 2.072063234351634531e+00 230 | 2.120064699240089112e+00 231 | 2.156065797906430603e+00 232 | 2.154065736869411385e+00 233 | 2.112064455092013571e+00 234 | 2.042062318796350251e+00 235 | 1.990060731833857233e+00 236 | 1.988060670796838236e+00 237 | 2.032062013611255047e+00 238 | 2.078063417462690854e+00 239 | 2.096063966795861599e+00 240 | 2.074063295388652861e+00 241 | 2.014061464278084745e+00 242 | 1.952059572130497189e+00 243 | 1.926058778649250680e+00 244 | 1.954059633167515964e+00 245 | 2.010061342204047197e+00 246 | 2.010061342204047197e+00 247 | 2.050062562944425792e+00 248 | 2.054062685018463341e+00 249 | 2.020061647389141513e+00 250 | 1.964059938352610724e+00 251 | 1.928058839686269677e+00 252 | 1.944059327982421204e+00 253 | 2.004061159092989985e+00 254 | 2.068063112277596538e+00 255 | 2.102064149906918367e+00 256 | 2.092063844721824051e+00 257 | 2.050062562944425792e+00 258 | 2.006061220130009204e+00 259 | 2.008061281167027978e+00 260 | 2.060062868129520552e+00 261 | 2.132065065462203091e+00 262 | 2.184066652424695665e+00 263 | 2.194066957609790425e+00 264 | 2.164066042054506145e+00 265 | 2.116064577166051119e+00 266 | 2.098064027832880374e+00 267 | 2.138065248573259414e+00 268 | 2.216067629016999163e+00 269 | 2.286069765312662039e+00 270 | 2.318070741904965537e+00 271 | 2.308070436719870333e+00 272 | 2.266069154942472519e+00 273 | 2.234068178350169465e+00 274 | 2.258068910794396977e+00 275 | 2.328071047090059853e+00 276 | 2.400073244422742391e+00 277 | 2.438074404126102657e+00 278 | 2.432074221015045445e+00 279 | 2.390072939237647631e+00 280 | 2.390072939237647631e+00 281 | 2.338071352275155057e+00 282 | 2.324070925016021860e+00 283 | 2.364072145756401344e+00 284 | 2.426074037903989122e+00 285 | 2.466075258644368162e+00 286 | 2.470075380718405711e+00 287 | 2.436074343089083438e+00 288 | 2.378072573015534097e+00 289 | 2.338071352275155057e+00 290 | 2.354071840571306584e+00 291 | 2.408073488570817933e+00 292 | 2.460075075533310951e+00 293 | 2.480075685903500471e+00 294 | 2.462075136570330169e+00 295 | 2.410073549607837151e+00 296 | 2.356071901608325359e+00 297 | 2.346071596423230599e+00 298 | 2.388072878200628413e+00 299 | 2.446074648274178642e+00 300 | 2.480075685903500471e+00 301 | 2.478075624866481697e+00 302 | 2.438074404126102657e+00 303 | 2.380072634052552871e+00 304 | 2.346071596423230599e+00 305 | 2.368072267830438893e+00 306 | 2.424073976866969904e+00 307 | 2.472075441755424485e+00 308 | 2.486075869014557682e+00 309 | 2.462075136570330169e+00 310 | 2.406073427533799602e+00 311 | 2.356071901608325359e+00 312 | 2.354071840571306584e+00 313 | 2.400073244422742391e+00 314 | 2.400073244422742391e+00 315 | 2.456074953459272958e+00 316 | 2.486075869014557682e+00 317 | 2.478075624866481697e+00 318 | 2.434074282052064664e+00 319 | 2.376072511978514878e+00 320 | 2.350071718497268591e+00 321 | 2.378072573015534097e+00 322 | 2.434074282052064664e+00 323 | 2.478075624866481697e+00 324 | 2.486075869014557682e+00 325 | 2.458075014496292177e+00 326 | 2.400073244422742391e+00 327 | 2.354071840571306584e+00 328 | 2.360072023682363351e+00 329 | 2.410073549607837151e+00 330 | 2.462075136570330169e+00 331 | 2.488075930051576456e+00 332 | 2.474075502792443704e+00 333 | 2.428074098941007453e+00 334 | 2.370072328867458111e+00 335 | 2.350071718497268591e+00 336 | 2.386072817163609638e+00 337 | 2.442074526200140649e+00 338 | 2.482075746940519689e+00 339 | 2.484075807977538464e+00 340 | 2.452074831385234965e+00 341 | 2.392073000274666406e+00 342 | 2.352071779534287366e+00 343 | 2.364072145756401344e+00 344 | 2.418073793755913137e+00 345 | 2.468075319681386937e+00 346 | 2.488075930051576456e+00 347 | 2.470075380718405711e+00 348 | 2.470075380718405711e+00 349 | 2.418073793755913137e+00 350 | 2.364072145756401344e+00 351 | 2.352071779534287366e+00 352 | 2.392073000274666406e+00 353 | 2.448074709311197417e+00 354 | 2.484075807977538464e+00 355 | 2.482075746940519689e+00 356 | 2.444074587237159424e+00 357 | 2.384072756126590864e+00 358 | 2.348071657460249373e+00 359 | 2.368072267830438893e+00 360 | 2.424073976866969904e+00 361 | 2.472075441755424485e+00 362 | 2.486075869014557682e+00 363 | 2.464075197607348944e+00 364 | 2.408073488570817933e+00 365 | 2.356071901608325359e+00 366 | 2.352071779534287366e+00 367 | 2.396073122348704398e+00 368 | 2.452074831385234965e+00 369 | 2.482075746940519689e+00 370 | 2.344071535386211380e+00 371 | 2.370072328867458111e+00 372 | 2.426074037903989122e+00 373 | 2.472075441755424485e+00 374 | 2.480075685903500471e+00 375 | 2.452074831385234965e+00 376 | 2.394073061311685624e+00 377 | 2.346071596423230599e+00 378 | 2.350071718497268591e+00 379 | 2.398073183385723617e+00 380 | 2.452074831385234965e+00 381 | 2.478075624866481697e+00 382 | 2.466075258644368162e+00 383 | 2.418073793755913137e+00 384 | 2.358071962645344577e+00 385 | 2.336071291238135839e+00 386 | 2.368072267830438893e+00 387 | 2.426074037903989122e+00 388 | 2.426074037903989122e+00 389 | 2.466075258644368162e+00 390 | 2.470075380718405711e+00 391 | 2.436074343089083438e+00 392 | 2.376072511978514878e+00 393 | 2.330071108127079071e+00 394 | 2.338071352275155057e+00 395 | 2.388072878200628413e+00 396 | 2.436074343089083438e+00 397 | 2.454074892422254184e+00 398 | 2.432074221015045445e+00 399 | 2.372072389904476886e+00 400 | 2.304070314645832784e+00 401 | 2.276069460127567723e+00 402 | 2.302070253608814010e+00 403 | 2.348071657460249373e+00 404 | 2.372072389904476886e+00 405 | 2.356071901608325359e+00 406 | 2.300070192571795236e+00 407 | 2.216067629016999163e+00 408 | 2.156065797906430603e+00 409 | 2.148065553758354618e+00 410 | 2.184066652424695665e+00 411 | 2.224067873165074705e+00 412 | 2.232068117313150690e+00 413 | 2.200067140720847192e+00 414 | 2.134065126499221865e+00 415 | 2.064062990203558545e+00 416 | 2.034062074648274265e+00 417 | 2.054062685018463341e+00 418 | 2.100064088869899592e+00 419 | 2.128064943388165098e+00 420 | 2.118064638203069894e+00 421 | 2.070063173314615312e+00 422 | 2.070063173314615312e+00 423 | 1.998060975981932996e+00 424 | 1.948059450056459196e+00 425 | 1.948059450056459196e+00 426 | 1.986060609759819240e+00 427 | 2.032062013611255047e+00 428 | 2.046062440870388244e+00 429 | 2.024061769463179505e+00 430 | 1.968060060426648716e+00 431 | 1.914058412427137146e+00 432 | 1.902058046205023389e+00 433 | 1.940059205908383433e+00 434 | 2.004061159092989985e+00 435 | 2.050062562944425792e+00 436 | 2.054062685018463341e+00 437 | 2.022061708426160731e+00 438 | 1.972060182500686709e+00 439 | 1.948059450056459196e+00 440 | 1.978060365611743476e+00 441 | 2.046062440870388244e+00 442 | 2.106064271980956359e+00 443 | 2.130065004425183872e+00 444 | 2.114064516129032345e+00 445 | 2.068063112277596538e+00 446 | 2.032062013611255047e+00 447 | 2.044062379833369025e+00 448 | 2.104064210943937585e+00 449 | 2.174066347239600905e+00 450 | 2.214067567979979945e+00 451 | 2.214067567979979945e+00 452 | 2.176066408276620123e+00 453 | 2.128064943388165098e+00 454 | 2.116064577166051119e+00 455 | 2.162065981017486926e+00 456 | 2.230068056276131472e+00 457 | 2.230068056276131472e+00 458 | 2.282069643238624046e+00 459 | 2.294070009460738024e+00 460 | 2.268069215979491737e+00 461 | 2.214067567979979945e+00 462 | 2.182066591387676446e+00 463 | 2.202067201757865966e+00 464 | 2.264069093905453744e+00 465 | 2.324070925016021860e+00 466 | 2.350071718497268591e+00 467 | 2.336071291238135839e+00 468 | 2.288069826349681257e+00 469 | 2.238068300424207457e+00 470 | 2.232068117313150690e+00 471 | 2.280069582201605716e+00 472 | 2.342071474349193050e+00 473 | 2.382072695089572090e+00 474 | 2.382072695089572090e+00 475 | 2.344071535386211380e+00 476 | 2.286069765312662039e+00 477 | 2.256068849757378203e+00 478 | 2.280069582201605716e+00 479 | 2.342071474349193050e+00 480 | 2.392073000274666406e+00 481 | 2.408073488570817933e+00 482 | 2.384072756126590864e+00 483 | 2.328071047090059853e+00 484 | 2.276069460127567723e+00 485 | 2.276069460127567723e+00 486 | 2.326070986053041079e+00 487 | 2.386072817163609638e+00 488 | 2.416073732718893918e+00 489 | 2.408073488570817933e+00 490 | 2.364072145756401344e+00 491 | 2.364072145756401344e+00 492 | 2.302070253608814010e+00 493 | 2.276069460127567723e+00 494 | 2.308070436719870333e+00 495 | 2.368072267830438893e+00 496 | 2.414073671681875144e+00 497 | 2.422073915829951130e+00 498 | 2.392073000274666406e+00 499 | 2.332071169164097846e+00 500 | 2.284069704275643264e+00 501 | 2.292069948423719250e+00 502 | 2.346071596423230599e+00 503 | 2.402073305459761610e+00 504 | 2.428074098941007453e+00 505 | 2.414073671681875144e+00 506 | 2.364072145756401344e+00 507 | 2.304070314645832784e+00 508 | 2.284069704275643264e+00 509 | 2.322070863979003530e+00 510 | 2.382072695089572090e+00 511 | 2.424073976866969904e+00 512 | 2.426074037903989122e+00 513 | 2.390072939237647631e+00 514 | 2.328071047090059853e+00 515 | 2.288069826349681257e+00 516 | 2.302070253608814010e+00 517 | 2.356071901608325359e+00 518 | 2.408073488570817933e+00 519 | 2.428074098941007453e+00 520 | 2.408073488570817933e+00 521 | 2.352071779534287366e+00 522 | 2.296070070497757243e+00 523 | 2.282069643238624046e+00 524 | 2.324070925016021860e+00 525 | 2.324070925016021860e+00 526 | 2.380072634052552871e+00 527 | 2.414073671681875144e+00 528 | 2.410073549607837151e+00 529 | 2.368072267830438893e+00 530 | 2.304070314645832784e+00 531 | 2.266069154942472519e+00 532 | 2.284069704275643264e+00 533 | 2.338071352275155057e+00 534 | 2.384072756126590864e+00 535 | 2.396073122348704398e+00 536 | 2.368072267830438893e+00 537 | 2.308070436719870333e+00 538 | 2.250068666646320992e+00 539 | 2.242068422498245006e+00 540 | 2.284069704275643264e+00 541 | 2.336071291238135839e+00 542 | 2.364072145756401344e+00 543 | 2.350071718497268591e+00 544 | 2.300070192571795236e+00 545 | 2.232068117313150690e+00 546 | 2.196067018646809643e+00 547 | 2.214067567979979945e+00 548 | 2.264069093905453744e+00 549 | 2.302070253608814010e+00 550 | 2.306070375682851559e+00 551 | 2.270069277016510512e+00 552 | 2.202067201757865966e+00 553 | 2.144065431684316625e+00 554 | 2.134065126499221865e+00 555 | 2.172066286202582130e+00 556 | 2.218067690054017937e+00 557 | 2.238068300424207457e+00 558 | 2.218067690054017937e+00 559 | 2.218067690054017937e+00 560 | 2.164066042054506145e+00 561 | 2.094063905758842381e+00 562 | 2.060062868129520552e+00 563 | 2.076063356425672080e+00 564 | 2.124064821314127105e+00 565 | 2.160065919980468152e+00 566 | 2.160065919980468152e+00 567 | 2.120064699240089112e+00 568 | 2.052062623981445011e+00 569 | 1.996060914944914000e+00 570 | 1.988060670796838236e+00 571 | 2.028061891537217498e+00 572 | 2.078063417462690854e+00 573 | 2.104064210943937585e+00 574 | 2.090063783684804832e+00 575 | 2.040062257759331033e+00 576 | 1.980060426648762473e+00 577 | 1.958059755241553956e+00 578 | 1.992060792870876229e+00 579 | 2.056062746055482560e+00 580 | 2.110064394054994352e+00 581 | 2.126064882351145879e+00 582 | 2.104064210943937585e+00 583 | 2.054062685018463341e+00 584 | 2.024061769463179505e+00 585 | 2.046062440870388244e+00 586 | 2.112064455092013571e+00 587 | 2.182066591387676446e+00 588 | 2.218067690054017937e+00 589 | 2.212067506942961170e+00 590 | 2.168066164128544138e+00 591 | 2.126064882351145879e+00 592 | 2.130065004425183872e+00 593 | 2.130065004425183872e+00 594 | 2.188066774498733658e+00 595 | 2.272069338053529730e+00 596 | 2.336071291238135839e+00 597 | 2.356071901608325359e+00 598 | 2.334071230201117064e+00 599 | 2.292069948423719250e+00 600 | 2.278069521164586497e+00 601 | 2.318070741904965537e+00 602 | 2.390072939237647631e+00 603 | 2.446074648274178642e+00 604 | 2.464075197607348944e+00 605 | 2.442074526200140649e+00 606 | 2.388072878200628413e+00 607 | 2.342071474349193050e+00 608 | 2.346071596423230599e+00 609 | 2.396073122348704398e+00 610 | 2.452074831385234965e+00 611 | 2.480075685903500471e+00 612 | 2.468075319681386937e+00 613 | 2.422073915829951130e+00 614 | 2.366072206793420118e+00 615 | 2.344071535386211380e+00 616 | 2.376072511978514878e+00 617 | 2.434074282052064664e+00 618 | 2.476075563829462478e+00 619 | 2.482075746940519689e+00 620 | 2.452074831385234965e+00 621 | 2.392073000274666406e+00 622 | 2.350071718497268591e+00 623 | 2.360072023682363351e+00 624 | 2.412073610644855925e+00 625 | 2.464075197607348944e+00 626 | 2.488075930051576456e+00 627 | 2.488075930051576456e+00 628 | 2.472075441755424485e+00 629 | 2.422073915829951130e+00 630 | 2.366072206793420118e+00 631 | 2.350071718497268591e+00 632 | 2.388072878200628413e+00 633 | 2.446074648274178642e+00 634 | 2.484075807977538464e+00 635 | 2.484075807977538464e+00 636 | 2.446074648274178642e+00 637 | 2.388072878200628413e+00 638 | 2.350071718497268591e+00 639 | 2.368072267830438893e+00 640 | 2.422073915829951130e+00 641 | 2.470075380718405711e+00 642 | 2.488075930051576456e+00 643 | 2.466075258644368162e+00 644 | 2.414073671681875144e+00 645 | 2.360072023682363351e+00 646 | 2.354071840571306584e+00 647 | 2.396073122348704398e+00 648 | 2.452074831385234965e+00 649 | 2.486075869014557682e+00 650 | 2.480075685903500471e+00 651 | 2.440074465163121431e+00 652 | 2.380072634052552871e+00 653 | 2.350071718497268591e+00 654 | 2.374072450941496104e+00 655 | 2.430074159978026671e+00 656 | 2.476075563829462478e+00 657 | 2.486075869014557682e+00 658 | 2.462075136570330169e+00 659 | 2.406073427533799602e+00 660 | 2.356071901608325359e+00 661 | 2.356071901608325359e+00 662 | 2.356071901608325359e+00 663 | 2.404073366496780384e+00 664 | 2.458075014496292177e+00 665 | 2.486075869014557682e+00 666 | 2.476075563829462478e+00 667 | 2.432074221015045445e+00 668 | 2.372072389904476886e+00 669 | 2.348071657460249373e+00 670 | 2.378072573015534097e+00 671 | 2.434074282052064664e+00 672 | 2.476075563829462478e+00 673 | 2.484075807977538464e+00 674 | 2.452074831385234965e+00 675 | 2.394073061311685624e+00 676 | 2.350071718497268591e+00 677 | 2.356071901608325359e+00 678 | 2.406073427533799602e+00 679 | 2.460075075533310951e+00 680 | 2.482075746940519689e+00 681 | 2.468075319681386937e+00 682 | 2.418073793755913137e+00 683 | 2.360072023682363351e+00 684 | 2.342071474349193050e+00 685 | 2.378072573015534097e+00 686 | 2.436074343089083438e+00 687 | 2.474075502792443704e+00 688 | 2.474075502792443704e+00 689 | 2.438074404126102657e+00 690 | 2.378072573015534097e+00 691 | 2.338071352275155057e+00 692 | 2.352071779534287366e+00 693 | 2.406073427533799602e+00 694 | 2.456074953459272958e+00 695 | 2.474075502792443704e+00 696 | 2.474075502792443704e+00 697 | 2.454074892422254184e+00 698 | 2.400073244422742391e+00 699 | 2.342071474349193050e+00 700 | 2.328071047090059853e+00 701 | 2.366072206793420118e+00 702 | 2.420073854792931911e+00 703 | 2.450074770348216191e+00 704 | 2.438074404126102657e+00 705 | 2.388072878200628413e+00 706 | 2.312070558793908326e+00 707 | 2.258068910794396977e+00 708 | 2.256068849757378203e+00 709 | 2.290069887386700032e+00 710 | 2.316070680867946319e+00 711 | 2.310070497756889552e+00 712 | 2.264069093905453744e+00 713 | 2.186066713461714439e+00 714 | 2.110064394054994352e+00 715 | 2.080063478499710072e+00 716 | 2.102064149906918367e+00 717 | 2.146065492721335399e+00 718 | 2.170066225165562912e+00 719 | 2.152065675832392611e+00 720 | 2.094063905758842381e+00 721 | 2.018061586352122738e+00 722 | 1.968060060426648716e+00 723 | 1.970060121463667713e+00 724 | 2.014061464278084745e+00 725 | 2.058062807092501334e+00 726 | 2.074063295388652861e+00 727 | 2.050062562944425792e+00 728 | 1.998060975981932996e+00 729 | 1.954059633167515964e+00 730 | 1.954059633167515964e+00 731 | 1.954059633167515964e+00 732 | 2.006061220130009204e+00 733 | 2.076063356425672080e+00 734 | 2.120064699240089112e+00 735 | 2.126064882351145879e+00 736 | 2.094063905758842381e+00 737 | 2.048062501907407018e+00 738 | 2.034062074648274265e+00 739 | 2.078063417462690854e+00 740 | 2.150065614795373392e+00 741 | 2.210067445905941952e+00 742 | 2.232068117313150690e+00 743 | 2.212067506942961170e+00 744 | 2.166066103091524919e+00 745 | 2.134065126499221865e+00 746 | 2.154065736869411385e+00 747 | 2.220067751091036712e+00 748 | 2.284069704275643264e+00 749 | 2.318070741904965537e+00 750 | 2.310070497756889552e+00 751 | 2.266069154942472519e+00 752 | 2.216067629016999163e+00 753 | 2.210067445905941952e+00 754 | 2.258068910794396977e+00 755 | 2.322070863979003530e+00 756 | 2.366072206793420118e+00 757 | 2.370072328867458111e+00 758 | 2.334071230201117064e+00 759 | 2.276069460127567723e+00 760 | 2.242068422498245006e+00 761 | 2.264069093905453744e+00 762 | 2.324070925016021860e+00 763 | 2.378072573015534097e+00 764 | 2.378072573015534097e+00 765 | 2.396073122348704398e+00 766 | 2.374072450941496104e+00 767 | 2.318070741904965537e+00 768 | 2.264069093905453744e+00 769 | 2.260068971831416196e+00 770 | 2.308070436719870333e+00 771 | 2.368072267830438893e+00 772 | 2.402073305459761610e+00 773 | 2.396073122348704398e+00 774 | 2.352071779534287366e+00 775 | 2.290069887386700032e+00 776 | 2.260068971831416196e+00 777 | 2.288069826349681257e+00 778 | 2.348071657460249373e+00 779 | 2.396073122348704398e+00 780 | 2.408073488570817933e+00 781 | 2.380072634052552871e+00 782 | 2.320070802941984311e+00 783 | 2.270069277016510512e+00 784 | 2.272069338053529730e+00 785 | 2.324070925016021860e+00 786 | 2.384072756126590864e+00 787 | 2.412073610644855925e+00 788 | 2.402073305459761610e+00 789 | 2.354071840571306584e+00 790 | 2.292069948423719250e+00 791 | 2.272069338053529730e+00 792 | 2.308070436719870333e+00 793 | 2.368072267830438893e+00 794 | 2.412073610644855925e+00 795 | 2.418073793755913137e+00 796 | 2.384072756126590864e+00 797 | 2.322070863979003530e+00 798 | 2.322070863979003530e+00 799 | 2.278069521164586497e+00 800 | 2.288069826349681257e+00 801 | 2.342071474349193050e+00 802 | 2.396073122348704398e+00 803 | 2.416073732718893918e+00 804 | 2.398073183385723617e+00 805 | 2.344071535386211380e+00 806 | 2.282069643238624046e+00 807 | 2.266069154942472519e+00 808 | 2.302070253608814010e+00 809 | 2.358071962645344577e+00 810 | 2.394073061311685624e+00 811 | 2.390072939237647631e+00 812 | 2.348071657460249373e+00 813 | 2.280069582201605716e+00 814 | 2.238068300424207457e+00 815 | 2.250068666646320992e+00 816 | 2.300070192571795236e+00 817 | 2.344071535386211380e+00 818 | 2.356071901608325359e+00 819 | 2.328071047090059853e+00 820 | 2.264069093905453744e+00 821 | 2.202067201757865966e+00 822 | 2.184066652424695665e+00 823 | 2.216067629016999163e+00 824 | 2.264069093905453744e+00 825 | 2.290069887386700032e+00 826 | 2.276069460127567723e+00 827 | 2.226067934202093479e+00 828 | 2.154065736869411385e+00 829 | 2.110064394054994352e+00 830 | 2.118064638203069894e+00 831 | 2.162065981017486926e+00 832 | 2.162065981017486926e+00 833 | 2.202067201757865966e+00 834 | 2.208067384868923178e+00 835 | 2.176066408276620123e+00 836 | 2.114064516129032345e+00 837 | 2.054062685018463341e+00 838 | 2.040062257759331033e+00 839 | 2.078063417462690854e+00 840 | 2.136065187536240639e+00 841 | 2.170066225165562912e+00 842 | 2.170066225165562912e+00 843 | 2.132065065462203091e+00 844 | 2.078063417462690854e+00 845 | 2.056062746055482560e+00 846 | 2.090063783684804832e+00 847 | 2.162065981017486926e+00 848 | 2.228067995239112697e+00 849 | 2.260068971831416196e+00 850 | 2.248068605609302217e+00 851 | 2.204067262794885185e+00 852 | 2.172066286202582130e+00 853 | 2.192066896572771650e+00 854 | 2.266069154942472519e+00 855 | 2.348071657460249373e+00 856 | 2.400073244422742391e+00 857 | 2.406073427533799602e+00 858 | 2.372072389904476886e+00 859 | 2.328071047090059853e+00 860 | 2.320070802941984311e+00 861 | 2.366072206793420118e+00 862 | 2.428074098941007453e+00 863 | 2.470075380718405711e+00 864 | 2.474075502792443704e+00 865 | 2.438074404126102657e+00 866 | 2.380072634052552871e+00 867 | 2.380072634052552871e+00 868 | 2.342071474349193050e+00 869 | 2.358071962645344577e+00 870 | 2.412073610644855925e+00 871 | 2.462075136570330169e+00 872 | 2.480075685903500471e+00 873 | 2.460075075533310951e+00 874 | 2.408073488570817933e+00 875 | 2.354071840571306584e+00 876 | 2.346071596423230599e+00 877 | 2.390072939237647631e+00 878 | 2.446074648274178642e+00 879 | 2.480075685903500471e+00 880 | 2.476075563829462478e+00 881 | 2.436074343089083438e+00 882 | 2.378072573015534097e+00 883 | 2.346071596423230599e+00 884 | 2.370072328867458111e+00 885 | 2.426074037903989122e+00 886 | 2.472075441755424485e+00 887 | 2.486075869014557682e+00 888 | 2.460075075533310951e+00 889 | 2.406073427533799602e+00 890 | 2.356071901608325359e+00 891 | 2.356071901608325359e+00 892 | 2.402073305459761610e+00 893 | 2.456074953459272958e+00 894 | 2.486075869014557682e+00 895 | 2.476075563829462478e+00 896 | 2.432074221015045445e+00 897 | 2.374072450941496104e+00 898 | 2.350071718497268591e+00 899 | 2.378072573015534097e+00 900 | 2.436074343089083438e+00 901 | 2.436074343089083438e+00 902 | 2.478075624866481697e+00 903 | 2.486075869014557682e+00 904 | 2.456074953459272958e+00 905 | 2.398073183385723617e+00 906 | 2.354071840571306584e+00 907 | 2.360072023682363351e+00 908 | 2.410073549607837151e+00 909 | 2.464075197607348944e+00 910 | 2.488075930051576456e+00 911 | 2.474075502792443704e+00 912 | 2.426074037903989122e+00 913 | 2.368072267830438893e+00 914 | 2.350071718497268591e+00 915 | 2.386072817163609638e+00 916 | 2.442074526200140649e+00 917 | 2.482075746940519689e+00 918 | 2.484075807977538464e+00 919 | 2.450074770348216191e+00 920 | 2.390072939237647631e+00 921 | -------------------------------------------------------------------------------- /py_dict_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is to demostrates my proficiency manipulating python dictionaries 4 | 5 | # names of hurricanes 6 | names = ['Cuba I', 'San Felipe II Okeechobee', 'Bahamas', 'Cuba II', 'CubaBrownsville', 'Tampico', 'Labor Day', 'New England', 'Carol', 'Janet', 'Carla', 'Hattie', 'Beulah', 'Camille', 'Edith', 'Anita', 'David', 'Allen', 'Gilbert', 'Hugo', 'Andrew', 'Mitch', 'Isabel', 'Ivan', 'Emily', 'Katrina', 'Rita', 'Wilma', 'Dean', 'Felix', 'Matthew', 'Irma', 'Maria', 'Michael'] 7 | 8 | # months of hurricanes 9 | months = ['October', 'September', 'September', 'November', 'August', 'September', 'September', 'September', 'September', 'September', 'September', 'October', 'September', 'August', 'September', 'September', 'August', 'August', 'September', 'September', 'August', 'October', 'September', 'September', 'July', 'August', 'September', 'October', 'August', 'September', 'October', 'September', 'September', 'October'] 10 | 11 | # years of hurricanes 12 | years = [1924, 1928, 1932, 1932, 1933, 1933, 1935, 1938, 1953, 1955, 1961, 1961, 1967, 1969, 1971, 1977, 1979, 1980, 1988, 1989, 1992, 1998, 2003, 2004, 2005, 2005, 2005, 2005, 2007, 2007, 2016, 2017, 2017, 2018] 13 | 14 | # maximum sustained winds (mph) of hurricanes 15 | max_sustained_winds = [165, 160, 160, 175, 160, 160, 185, 160, 160, 175, 175, 160, 160, 175, 160, 175, 175, 190, 185, 160, 175, 180, 165, 165, 160, 175, 180, 185, 175, 175, 165, 180, 175, 160] 16 | 17 | # areas affected by each hurricane 18 | areas_affected = [['Central America', 'Mexico', 'Cuba', 'Florida', 'The Bahamas'], ['Lesser Antilles', 'The Bahamas', 'United States East Coast', 'Atlantic Canada'], ['The Bahamas', 'Northeastern United States'], ['Lesser Antilles', 'Jamaica', 'Cayman Islands', 'Cuba', 'The Bahamas', 'Bermuda'], ['The Bahamas', 'Cuba', 'Florida', 'Texas', 'Tamaulipas'], ['Jamaica', 'Yucatn Peninsula'], ['The Bahamas', 'Florida', 'Georgia', 'The Carolinas', 'Virginia'], ['Southeastern United States', 'Northeastern United States', 'Southwestern Quebec'], ['Bermuda', 'New England', 'Atlantic Canada'], ['Lesser Antilles', 'Central America'], ['Texas', 'Louisiana', 'Midwestern United States'], ['Central America'], ['The Caribbean', 'Mexico', 'Texas'], ['Cuba', 'United States Gulf Coast'], ['The Caribbean', 'Central America', 'Mexico', 'United States Gulf Coast'], ['Mexico'], ['The Caribbean', 'United States East coast'], ['The Caribbean', 'Yucatn Peninsula', 'Mexico', 'South Texas'], ['Jamaica', 'Venezuela', 'Central America', 'Hispaniola', 'Mexico'], ['The Caribbean', 'United States East Coast'], ['The Bahamas', 'Florida', 'United States Gulf Coast'], ['Central America', 'Yucatn Peninsula', 'South Florida'], ['Greater Antilles', 'Bahamas', 'Eastern United States', 'Ontario'], ['The Caribbean', 'Venezuela', 'United States Gulf Coast'], ['Windward Islands', 'Jamaica', 'Mexico', 'Texas'], ['Bahamas', 'United States Gulf Coast'], ['Cuba', 'United States Gulf Coast'], ['Greater Antilles', 'Central America', 'Florida'], ['The Caribbean', 'Central America'], ['Nicaragua', 'Honduras'], ['Antilles', 'Venezuela', 'Colombia', 'United States East Coast', 'Atlantic Canada'], ['Cape Verde', 'The Caribbean', 'British Virgin Islands', 'U.S. Virgin Islands', 'Cuba', 'Florida'], ['Lesser Antilles', 'Virgin Islands', 'Puerto Rico', 'Dominican Republic', 'Turks and Caicos Islands'], ['Central America', 'United States Gulf Coast (especially Florida Panhandle)']] 19 | 20 | # damages (USD($)) of hurricanes 21 | damages = ['Damages not recorded', '100M', 'Damages not recorded', '40M', '27.9M', '5M', 'Damages not recorded', '306M', '2M', '65.8M', '326M', '60.3M', '208M', '1.42B', '25.4M', 'Damages not recorded', '1.54B', '1.24B', '7.1B', '10B', '26.5B', '6.2B', '5.37B', '23.3B', '1.01B', '125B', '12B', '29.4B', '1.76B', '720M', '15.1B', '64.8B', '91.6B', '25.1B'] 22 | 23 | # deaths for each hurricane 24 | deaths = [90,4000,16,3103,179,184,408,682,5,1023,43,319,688,259,37,11,2068,269,318,107,65,19325,51,124,17,1836,125,87,45,133,603,138,3057,74] 25 | 26 | # 1 27 | # Update Recorded Damages 28 | conversion = {"M": 1000000, 29 | "B": 1000000000} 30 | updated_damages = [] 31 | 32 | for i in damages: 33 | if ('M' in i): 34 | i = i.replace('M','') 35 | updated_damages += [float(i)*conversion['M']] 36 | elif ('B' in i): 37 | i = i.replace('B','') 38 | updated_damages += [float(i)*conversion['B']] 39 | else: 40 | updated_damages += [i] 41 | #print(updated_damages) 42 | 43 | # test function by updating damages 44 | 45 | 46 | def update_string_list(string_list): 47 | updated_string_list = [] 48 | conversion = {'M': 1000000, 'B': 1000000000} 49 | for i in string_list: 50 | if ('M' in i): 51 | i = i.replace('M','') 52 | updated_string_list += [float(i)*conversion['M']] 53 | elif ('B' in i): 54 | i = i.replace('B','') 55 | updated_string_list += [float(i)*conversion['B']] 56 | else: 57 | updated_string_list += [i] 58 | return updated_string_list 59 | 60 | 61 | # 2 62 | # Create a Table 63 | 64 | # Create and view the hurricanes dictionary 65 | hurricane = {} 66 | 67 | def hurricane_dict_maker(name, month, year, max_sustained_wind, area_affected, death): 68 | for i in range(len(name)): 69 | hurricane[name[i]] = {'Name': name[i], 'Month': month[i], 'Year': year[i], 'Maximum Sustained Winds': max_sustained_wind[i], 'Area Affected': area_affected[i], 'Deaths': death[i]} 70 | return hurricane 71 | 72 | hurricanes = hurricane_dict_maker(names, months, years, max_sustained_winds,areas_affected, deaths) 73 | print(hurricanes) 74 | 75 | 76 | # 3 77 | # Organizing by Year 78 | 79 | #this for loop takes the values for each key in hurricanes and makes a list of the dictionary values 80 | # It also makes a list of the years that each hurricanes occured in 81 | years_of_hurricanes = [] 82 | hurricane_years = {} 83 | hurricane_names_data = [] 84 | for name in hurricanes: 85 | hurricane_names_data.append(hurricane[name]) 86 | years_of_hurricanes.append(hurricanes[name]['Year']) 87 | 88 | 89 | #print(hurricane_names_data) 90 | #print(years_of_hurricanes) 91 | 92 | 93 | # create a new dictionary of hurricanes with year and key 94 | 95 | # 4 96 | # Counting Damaged Areas 97 | 98 | def dict_by_year(hurricane_data): 99 | hurricanes_year = {} 100 | for cane in hurricanes: 101 | current_cane = hurricane_data[cane] 102 | if current_cane['Year'] not in hurricanes_year: 103 | hurricanes_year[current_cane['Year']] = current_cane 104 | elif current_cane['Year'] in hurricanes_year: 105 | multiple_cane = hurricanes_year[current_cane['Year']] 106 | hurricanes_year[current_cane['Year']] = [multiple_cane, current_cane] 107 | return hurricanes_year 108 | hurricanes_year = dict_by_year(hurricanes) 109 | 110 | #print(hurricanes_year[2005]) 111 | 112 | # create dictionary of areas to store the number of hurricanes involved in 113 | 114 | # This loop takes in a dictionary with the names of the hurricanes as keys and the data 115 | # associacted with that hurricane as a dictionary value. Then it outputs a nested list 116 | # of the areas affected by each hurricane. 117 | 118 | nested_list_of_affected_areas = [] 119 | for i in range(len(hurricane_names_data)-1): 120 | hurricane_i = hurricane_names_data[i] 121 | nested_list_of_affected_areas.append(hurricane_i['Area Affected']) 122 | 123 | #this loop takes that nested list and converts it to a single list 124 | affected_area_list = [] 125 | for areas in nested_list_of_affected_areas: 126 | for area in areas: 127 | affected_area_list.append(area) 128 | 129 | #this loop createes a list of the affected areas 130 | areas_affected = [] 131 | for area in affected_area_list: 132 | if area not in areas_affected: 133 | areas_affected.append(area) 134 | #print(areas_affected) 135 | 136 | #this function takes in a list of dictionary values associated with each hurricane and outputs 137 | # an other dictionary of the affected areas and the number of times it has been affected by a cat-5 hurricane 138 | def count_affected_area(hurricane_data): 139 | affected_areas = [] 140 | for i in range(len(hurricane_data)-1): 141 | hurricane_i = hurricane_names_data[i] 142 | affected_areas.append(hurricane_i['Area Affected']) 143 | count_affected_areas_dict = {} 144 | counted_area_list = [] 145 | affected_area_list = [] 146 | for areas in affected_areas: 147 | for area in areas: 148 | affected_area_list.append(area) 149 | for i in range(len(affected_area_list)): 150 | if affected_area_list[i] not in counted_area_list: 151 | count = 1 152 | count_affected_areas_dict[affected_area_list[i]] = count 153 | counted_area_list.append(str(affected_area_list[i])) 154 | if affected_area_list[i] in counted_area_list: 155 | count = affected_area_list.count(affected_area_list[i]) 156 | count_affected_areas_dict[affected_area_list[i]] = count 157 | return count_affected_areas_dict 158 | 159 | areas_affected_and_num = count_affected_area(hurricane_names_data) 160 | #print(areas_affected_and_num) 161 | 162 | # 5 163 | # Calculating Maximum Hurricane Count 164 | 165 | #this function counts which area is affected by the most number of hurricanes 166 | #takes in dictioanry: areas_affected_and_num and the list: affected_areas 167 | 168 | def area_most_affected(areas_and_num): 169 | #assume a benchmark 170 | max_area_count = areas_affected_and_num[areas_affected[2]] 171 | most_affected_areas = {} 172 | for i in range(len(areas_affected)-1): #compare each entry to the benchmark 173 | area = areas_affected[i] 174 | area_count = areas_and_num[areas_affected[i]] 175 | if max_area_count <= area_count: #the benchmark 176 | max_area_count = area_count 177 | most_affected_areas[area] = area_count 178 | return most_affected_areas 179 | 180 | 181 | #a quick note, the above function doesn't compare quantities within a 182 | # dictionary and updates a dictionary it compares items of a list and 183 | # updates that dictionary. 184 | 185 | ##print(areas_affected) 186 | # find most frequently affected area and the number of hurricanes involved in 187 | 188 | most_affected_areas_dict = area_most_affected(areas_affected_and_num) 189 | 190 | print(most_affected_areas_dict) 191 | 192 | # 6 193 | # Calculating the Deadliest Hurricane 194 | 195 | # This function sorts that hurricanes by name and deaths associated with each 196 | # hurricane using the list of data for each hurricane stored as a dictionary: 197 | # hurricane_names_data 198 | 199 | #print(hurricane_names_data) 200 | 201 | 202 | def name_and_death_dict_maker(hurricane_data): 203 | name_and_death_dict = {} 204 | for i in range(len(hurricane_data)-1): 205 | hurricane_i = hurricane_data[i] 206 | name_and_death_dict[hurricane_i['Name']] = hurricane_i['Deaths'] 207 | return name_and_death_dict 208 | 209 | name_and_death_dict = name_and_death_dict_maker(hurricane_names_data) 210 | #print(name_and_death_dict) 211 | 212 | 213 | 214 | #this function makes a dictionary that includes the most deadliy hurricanes 215 | def most_deadly_hurricane_finder(hurricane_data): 216 | hurricane_33 = hurricane_data[0] 217 | deaths_of_deadliest_cane = hurricane_0['Deaths'] 218 | deadliest_canes = {} 219 | hurricane_name_list = [] 220 | hurricane_deaths_list =[] 221 | for i in range(len(hurricane_data)-1): 222 | hurricane_i = hurricane_data[i] 223 | hurricane_i_names = hurricane_name_list.append(hurricane_i['Name']) 224 | hurricane_i_deaths = hurricane_deaths_list.append(hurricane_i['Deaths']) 225 | if deaths_of_deadliest_cane <= hurricane_i_deaths: 226 | deaths_of_deadliest_cane = hurricane_i_deaths 227 | deadliest_canes[hurricane_name_list[i]] = hurricane_deaths_list[i] 228 | 229 | return deadliest_canes 230 | 231 | 232 | deadliest_canes = most_deadly_hurricane_finder(hurricane_names_data) 233 | 234 | print(hurricane_names_data) 235 | print(deadliest_canes) -------------------------------------------------------------------------------- /randomPolygonGenerator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | #Written for generating vector graphics 4 | 5 | import matplotlib.pyplot as plt 6 | import matplotlib.path as pth 7 | import numpy as np 8 | 9 | def angleBetweenPoints(p1, p2): 10 | """ 11 | angleBetweenPoints(p1,p2): Find the angle of the vector pointing from point p1 to p2. 12 | Returns: angle in radians 13 | p1: 2d tuple or list specifying a point (x,y) 14 | p2: The second point, same format. 15 | """ 16 | 17 | #Pretty much just simple trig here. 18 | #If slope is infinite don't use trig and just set it to avoid dividing by 0. 19 | if (p2[0]-p1[0] != 0): 20 | slope = (p2[1]-p1[1])/(p2[0]-p1[0]) 21 | angle = np.arctan(slope) 22 | if (p2[0] < p1[0]): 23 | angle += np.pi 24 | else: 25 | angle = np.pi/2 26 | 27 | return angle 28 | 29 | def getLineParameters(p1,p2): 30 | returnList = [0,0] 31 | if (p1[0] == p2[0]): 32 | returnList[0] = "vertical" 33 | returnList[1] = p1[0] 34 | else: 35 | returnList[0] = (p2[1] - p1[1])/(p2[0]-p1[0]) 36 | returnList[1] = 0.5*((p1[1] + p2[1]) - returnList[0]*(p1[0] + p2[0])) 37 | return returnList 38 | 39 | def find_outer_stroke(pointArray, lineWidth): 40 | lineParameters = [] 41 | angles = [] 42 | 43 | for i, x in enumerate(pointArray): 44 | if i == len(pointArray) -1: 45 | lineParameters.append(getLineParameters(pointArray[i],pointArray[0])) 46 | angles.append(angleBetweenPoints(pointArray[i],pointArray[0])) 47 | else: 48 | lineParameters.append(getLineParameters(pointArray[i], pointArray[i+1])) 49 | angles.append(angleBetweenPoints(pointArray[i],pointArray[i+1])) 50 | 51 | transformVectors = [] 52 | 53 | transformedLineParameters = [] 54 | for i, x in enumerate(lineParameters): 55 | print([-1*(lineWidth / 2) * np.cos(angles[i]),(lineWidth / 2) * np.sin(angles[i])]) 56 | transformVectors.append([(lineWidth / 2) * np.sin(angles[i]),-1*(lineWidth / 2) * np.cos(angles[i])]) 57 | transformedLineParameters.append(transformLine(lineParameters[i], transformVectors[i])) 58 | print(angles) 59 | intersectPoints = np.zeros((len(transformedLineParameters),2)) 60 | for i, x in enumerate(transformedLineParameters): 61 | if i == len(transformedLineParameters) -1: 62 | intersectPoints[i] = findLineIntersection(transformedLineParameters[i], transformedLineParameters[0]) 63 | else: 64 | intersectPoints[i] = findLineIntersection(transformedLineParameters[i],transformedLineParameters[i+1]) 65 | 66 | return intersectPoints 67 | 68 | def findInnerStroke(pointArray, lineWidth): 69 | lineParameters = [] 70 | angles = [] 71 | 72 | for i, x in enumerate(pointArray): 73 | if i == len(pointArray) -1: 74 | lineParameters.append(getLineParameters(pointArray[i],pointArray[0])) 75 | angles.append(angleBetweenPoints(pointArray[i],pointArray[0])) 76 | else: 77 | lineParameters.append(getLineParameters(pointArray[i], pointArray[i+1])) 78 | angles.append(angleBetweenPoints(pointArray[i],pointArray[i+1])) 79 | 80 | transformVectors = [] 81 | 82 | transformedLineParameters = [] 83 | for i, x in enumerate(lineParameters): 84 | transformVectors.append([-1*(lineWidth / 2) * np.sin(angles[i]),(lineWidth / 2) * np.cos(angles[i])]) 85 | transformedLineParameters.append(transformLine(lineParameters[i], transformVectors[i])) 86 | 87 | intersectPoints = np.zeros((len(transformedLineParameters),2)) 88 | for i, x in enumerate(transformedLineParameters): 89 | if i == len(transformedLineParameters) -1: 90 | intersectPoints[i] = findLineIntersection(transformedLineParameters[i], transformedLineParameters[0]) 91 | else: 92 | intersectPoints[i] = findLineIntersection(transformedLineParameters[i],transformedLineParameters[i+1]) 93 | 94 | return intersectPoints 95 | 96 | def transformLine(parameters, transformVector): 97 | returnList = [0,0] 98 | if parameters[0] != "vertical": 99 | returnList[0] = parameters[0] 100 | returnList[1] = parameters[1] + transformVector[1] - parameters[0]*transformVector[0] 101 | else: 102 | returnList = ["vertical",parameters[1]+transformVector[0]] 103 | return returnList 104 | 105 | def findLineIntersection(parameters1, parameters2): 106 | intersectPoint = np.zeros(2) 107 | if (parameters1[0] == "vertical"): 108 | intersectPoint[0] = parameters1[1] 109 | intersectPoint[1] = parameters2[0]*intersectPoint[0] + parameters2[1] 110 | elif (parameters2[0] == "vertical"): 111 | intersectPoint[0] = parameters2[1] 112 | intersectPoint[1] = parameters1[0]*intersectPoint[0] + parameters1[1] 113 | else: 114 | intersectPoint[0] = (parameters2[1] - parameters1[1])/(parameters1[0] - parameters2[0]) 115 | intersectPoint[1] = parameters1[0] * intersectPoint[0] + parameters1[1] 116 | 117 | return intersectPoint 118 | 119 | 120 | ############################################################################################################################## 121 | 122 | #Dimensions for canvas, taken from rt345.eps 123 | X = 512 124 | Y = 409 125 | 126 | #Define colors 127 | white = (0xff, 0xff, 0xff) 128 | blue = (0x00, 0x00, 0xff) 129 | 130 | #Array for color values. Initialize to white. 131 | pvals = np.full((X,Y,3), 0xff, dtype='uint8') 132 | 133 | #Points for triangle. Note that eps file defines offset of [58,58] when drawing points on line 23 134 | #In principle this code should work for general points, although I will not be testing it thoroughly on anything but the provided. 135 | p1 = (58, 58) 136 | p2 = (458, 58) 137 | p3 = (458, 358) 138 | 139 | lineWidth = 20 140 | 141 | scaleFactor = 0.1 142 | 143 | pointArray = np.array([[p1[0],p1[1]],[p2[0],p2[1]],[p3[0],p3[1]]],dtype=np.int32) 144 | 145 | outerStrokePoints = findOuterStroke(pointArray, lineWidth) 146 | 147 | innerStrokePoints = findInnerStroke(pointArray, lineWidth) 148 | 149 | print(outerStrokePoints) 150 | 151 | outerPath = pth.Path(outerStrokePoints) 152 | 153 | innerPath = pth.Path(innerStrokePoints) 154 | 155 | for i, x in enumerate(pvals): 156 | for j, y in enumerate(x): 157 | if (outerPath.contains_point((i,j))) and not innerPath.contains_point((i,j)): 158 | pvals[i,j] = blue 159 | 160 | #Transpose to proper format for drawing 161 | plotarr = np.flipud(pvals.transpose(1,0,2)) 162 | 163 | fig, ax = plt.subplots() 164 | picture = ax.imshow(plotarr, interpolation='none') 165 | ax.axis('off') 166 | fig.show() 167 | fig.canvas.draw() 168 | input("\nPress to exit...\n") -------------------------------------------------------------------------------- /relaxation_method.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This program approximates a simple parallel plate capacitor 4 | # given a static arrangement. The light portion is positive and 5 | # the dark portion is negative. You can see the even very close to 6 | # the edges it approximates to an infinte parallel plate capacitor 7 | # rather quickly 8 | 9 | # What is most interesting about this program is that is able to 10 | # solve any static pototential given sufficient boundary conditions. 11 | 12 | # WIlliam Murphy 13 | # 01Jun22 14 | 15 | import time 16 | import numpy as np 17 | import matplotlib.pyplot as plt 18 | 19 | 20 | # Initial Parameters of the space 21 | 22 | ITER = 60000 # Number of iteration for relaxation 23 | 24 | GRID = 600 # number of units for square grid 25 | 26 | P_WI = 0.05 # Plate Thickness 27 | 28 | P_TH = 0.05 # plate width as fraction of grid size 29 | 30 | GAP = 2.0 * P_WI # Plate Gap as a fraction of grid size, 31 | # and equal to plate width 32 | 33 | VOLT = 10.0 34 | 35 | off_set = 17 36 | 37 | # __Geometry of the capacitors is established__ 38 | # 39 | # Width of Electrodes (Defined as the difference between two points) 40 | clx = int(0.5*GRID*(1.0 - P_TH)) # Left side limit 41 | crx = GRID - clx #Right side limit 42 | 43 | # Gap 44 | cap_th = (2.0* GAP) *GRID 45 | 46 | # Left Electrode 47 | ctT = int(0.5*(GRID - cap_th)) # The top capacitors top 48 | cbT = int(ctT + GRID * P_WI) # The top capacitors bottom 49 | 50 | # Bottom Elctrode 51 | #ctB = int(0.5*(GRID + cap_th)) - off_set 52 | 53 | ctB = int(ctT + GRID * (GAP + P_WI)) - off_set # The bottom capacitors top 54 | #cbB = int(ctB + GRID * P_WI) 55 | 56 | cbB = GRID - ctT - off_set # The bottom capacitors bottom 57 | 58 | # Initial Matrix 59 | A = np.zeros((GRID, GRID)) 60 | 61 | # Voltage is put on the plate 62 | A[ctT:cbT, clx:crx] = -VOLT #Top capacitor is negative voltage 63 | A[ctB:cbB, clx:crx] = VOLT #Bottom capacitor is positive voltage 64 | 65 | #_______________________________________________ 66 | 67 | # This function computes each point by averaging the 68 | # points above, below and on each side via the roll() 69 | # method. It then redefines the boundary conditions 70 | # explicitly, via slicing. 71 | 72 | #def roll_avg(A): 73 | for i in range(ITER): 74 | 75 | # Averaging via np.roll 76 | A = (np.roll(A, -1, axis=0)+np.roll(A, 1, axis=0)+np.roll(A, -1, axis=1)+np.roll(A, 1, axis=1))/4 77 | 78 | # Reset the Boundary Conditions 79 | # ___________________________________________ 80 | 81 | # The electrodes 82 | A[ctT:cbT, clx:crx] = +VOLT #Top 83 | A[ctB:cbB, clx:crx] = -VOLT*3 #Bottom 84 | 85 | # The edges 86 | A[0] = 0 87 | A[GRID-1] = 0 88 | A[:,0] = 0 89 | A[:,GRID - 1] = 0 90 | 91 | # return b 92 | 93 | # For loop that implements the relaxation method 94 | 95 | #for i in range(ITER): 96 | # A = roll_avg(A) 97 | 98 | 99 | # _______Plotting_______ 100 | fig, ax = plt.subplots() 101 | 102 | x = 0.3 * GRID 103 | y = 0.94 * GRID 104 | 105 | ax.set_title('Approximation of a Dipole') 106 | ax.axis('off') 107 | ax.text(x, y,'''-Orange is 0 voltage 108 | -Light is positive 109 | -Dark is negative''') 110 | ax.imshow(A, interpolation='none', cmap='CMRmap') 111 | plt.show() 112 | 113 | 114 | -------------------------------------------------------------------------------- /socket_2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Author : William Murphy, with help from Professor Lipman 4 | # Date : 07May22 5 | 6 | # Description : 7 | # 8 | # This program creates a socket server, and sends 9 | # the current time to any client that connects to 10 | # the port 55555. This program is listening to all 11 | # availble IPv4 addresses possible, though it is shut 12 | # immediately after sending the data packet. 13 | 14 | 15 | import socket 16 | import time 17 | 18 | 19 | #Creates a socket and binds to a TCP port "prt" 20 | 21 | def bind_port(prt): 22 | 23 | host = '' #Bind to all available interfaces 24 | 25 | #Creates a socket, binds to it and listens 26 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 27 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 28 | s.bind((host, prt)) 29 | s.listen(1) 30 | 31 | return(s) 32 | 33 | 34 | #Creating a packet of data to send 35 | seconds = time.time() 36 | local_time = time.ctime(seconds) 37 | time_str = 'Local time: '+str(local_time) 38 | msg = str.encode(time_str, 'utf-8') 39 | 40 | print('Waiting for connection to be established...') 41 | 42 | #Defining the TCP port to bind to 43 | port = 55555 44 | 45 | #Naming the socket and inputting the port 46 | thesocket = bind_port(port) 47 | 48 | #Sending the data (The current time) 49 | connection, peer = thesocket.accept() 50 | connection.sendall(msg) 51 | connection.shutdown(socket.SHUT_RDWR) 52 | connection.close() 53 | 54 | print('Data Packet Sent') 55 | -------------------------------------------------------------------------------- /statistics_admission_rates.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This program is written as a kind of journal entry, accomplishing 5 | # tasks that are labels a) - g) 6 | 7 | # William Murphy 8 | # 25May22 9 | 10 | 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | from scipy import stats 14 | from scipy import special 15 | 16 | 17 | N = 787 18 | N_a = 146 19 | 20 | 21 | # a) The best estimate, P, of the admission probability, p_a, is N_a/N, so N_a = N*p. 22 | # A repeated admissions process with N as given above and actual admission 23 | # probability equal to p will produce values for NA drawn from a distribution. 24 | # What is the standard deviation sigma_A of this distribution? 25 | 26 | p_a = round(N_a/N, 3) 27 | q_a = 1-p_a 28 | mu_a = N*p_a 29 | sigma_a = round(np.sqrt(N * p_a * q_a),3) 30 | print('Calculated Standard Deviation is '+str(sigma_a)+' simga') 31 | print(str(p_a)+'% is the approximate probability of getting in') 32 | print('') 33 | 34 | # b) What is the 1-standard deviation uncertainty in p corresponding to σA? 35 | 36 | err_a = sigma_a/N 37 | print('Standard Error is ±'+str(round(err_a, 4))) 38 | print('') 39 | 40 | approx_a = [p_a - err_a, p_a-err_a] 41 | 42 | # c) Assume p is the exact admission probability. In other words, neglect the 43 | # uncertainty calculated above. Using binom.pmf(), compute the probability 44 | # that from a randomly selected group of 154 applicants, 48 or more are admitted. 45 | 46 | n = 154 47 | x = np.arange(0,n) 48 | 49 | binom_dist = [stats.binom.pmf(i, n, p_a) for i in x] 50 | prob_more_48 = round(np.sum(binom_dist[48:]), 6) 51 | 52 | print('The Probability of letting in more than 48 applicants is '+str(prob_more_48)) 53 | print('') 54 | 55 | 56 | # d) Usually (normally?), a Gaussian is a good approximation to a binomial 57 | # distribution. However, sometimes you can run into trouble if you are looking 58 | # at the tails of the distributions. Use erfc() to calculate the probability 59 | # from the previous part using a Gaussian approximation. By what factor is the 60 | # resulting answer too small? 61 | 62 | #The Number of admissions 63 | w = 48 64 | 65 | #The expected number of admissions, and standard deviation 66 | mu_c = n*p_a 67 | sigma_c = np.sqrt(154*p_a*q_a) 68 | print(sigma_c) 69 | print('The expected mean is '+str(mu_c)+' and the standard deviation is '+str(sigma_c)) 70 | 71 | #Difference between measurement and expectation 72 | outcome_diff = w - mu_c 73 | print('The difference between the number of admissions \n and the expected mean value is '+str(outcome_diff)) 74 | 75 | sd_c = outcome_diff/sigma_c 76 | print('That is a difference of :'+str(round(sd_c,5))+' stadard deviations') 77 | 78 | #The erfc giving it gaussian approximation 79 | erfc = 0.5 * special.erfc(sd_c) 80 | print('The Complimentary Error Function: '+str(round(erfc, 11))) 81 | 82 | #The order of magnitude the erfc is off by 83 | mag_diff = np.log10(erfc) - np.log10(prob_more_48) 84 | print('The gaussian approximation is off by '+str(round(mag_diff, 3))+' orders of magnitude') 85 | print('') 86 | 87 | 88 | 89 | # e) From a group of 154 applicants, 48 are admitted. Find the best estimate, 90 | # p_g, of the admission probability for this group, and the 1-standard deviation 91 | # uncertainty in p_g 92 | 93 | n = 154 94 | n_a = 48 95 | 96 | #The best estimate is the measurement itself 97 | p_g = n_a/n 98 | q_g = 1- p_g 99 | mu_g = n*p_g 100 | sigma_g = np.sqrt(n*p_g*q_g) 101 | err_g = sigma_g/n 102 | approx_g = [round(p_g-err_g, 4), round(p_g + err_g, 4)] 103 | print('The approximate probility of admission for the group with 154 applicants\n is between '+str(round(p_g,4))+' ± '+str(round(err_g,4))) 104 | 105 | 106 | # f) Find the best estimate, p_n, for the admission probability of applicants not 107 | # in the group of 154, and the corresponding 1-standard deviation uncertainty 108 | 109 | # probability of a random applicant is selected from 633 applicants given prob is 110 | # 18% and 48 out of 154 have been selected already 111 | 112 | # Number of students applications left after 154 113 | N_n = N - n 114 | # Approximate number of open positions minus the 48 already distributed 115 | n_n = N*p_a - n_a 116 | 117 | 118 | p_n = n_n/N_n 119 | q_n = 1-p_n 120 | mu_n = N_n*p_n 121 | sigma_n = np.sqrt(N_n*p_n*q_n) 122 | err_n = sigma_n/N_n 123 | 124 | approx_n = [round(p_n-err_n, 4), round(p_n + err_n, 4)] 125 | 126 | print('The approximate probility of admission for the group with '+str(N_n)+' applicants \n is between '+str(round(p_n,4))+' ± '+str(round(err_n,4))) 127 | 128 | 129 | # g) Turn in a plot showing the three Gaussian approximations to the distributions 130 | # of p_n , p, and p_g in different colors. Make the areas of the Gaussians 131 | # proportional to the populations of the corresponding groups. 132 | 133 | def normal_dist(x, mu, sigma): 134 | amp = (1/(sigma*np.sqrt(2*np.pi))) 135 | prob_density_func = amp * np.exp(-1*((x-mu)/(2*sigma))**2) 136 | return prob_density_func 137 | 138 | 139 | x_633 = np.linspace(0, 633, 1000) 140 | x_787 = np.linspace(0, 787, 1000) 141 | x_154 = np.linspace(0, 154, 1000) 142 | 143 | # p_n 144 | pdf_n = (633/787)*normal_dist(x_633, 98, 9.9) 145 | 146 | # p_g 147 | pdf_g = (154/787)*normal_dist(x_154, mu_g, sigma_g) 148 | 149 | # p 150 | pdf_p = normal_dist(x_787, mu_a, sigma_a) 151 | 152 | fig, ax = plt.subplots() 153 | 154 | gaussian_1, = ax.plot(x_633, pdf_n, label='Group of 633') 155 | gaussian_2, = ax.plot(x_787, pdf_p, label='Whole Group') 156 | gaussian_3, = ax.plot(x_154, pdf_g, label='Group of 154') 157 | 158 | ax.set_title('Gaussian Approximations \n for the Probability of Graduate School Admission') 159 | 160 | ax.set_ylabel('Probability') 161 | ax.set_xlabel('Number of Students') 162 | ax.set_xlim(0,250) 163 | ax.legend(loc='best') 164 | 165 | plt.show() 166 | 167 | -------------------------------------------------------------------------------- /string_manipulation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # This is a program with several objectives 5 | # 6 | # a. Prompts the user for a string with at least 3 words 7 | # b. Rejects the string and reprompts if the string has fewer than three words 8 | # c. Prints the words in the string, one per line 9 | # d. Prints the first three characters of the string 10 | # e. Prints the last three characters of the string 11 | # (not counting the newline character) 12 | # f. Prints the first half of the string 13 | # (include any characters on the boundary) 14 | # g. Prints the last half of the string 15 | # (include any characters on the boundary) 16 | # h. Prints the string with the words in reverse order 17 | # i. Prints the string with the words alphabetized 18 | # j. Prints each character in the string, one per line 19 | # k. Prints hexadecimal values for each character in the string, 20 | # one line per character 21 | # 22 | # Author - Billy Murphy 12 April 22 23 | # 24 | 25 | # This while loop is both objective a & b 26 | while True: 27 | word_str = input('Please enter a string that is at least 3 words long: ') 28 | i_lst = word_str.rsplit(' ') 29 | if len(i_lst) >= 2: 30 | word_lst = word_str.rsplit(' ') 31 | break 32 | 33 | #Objectives a and b are intimately linked since b depends on a reprompting. I chose to not 34 | #change the prompt after it was rejected, since the directions for the kind of string the 35 | #the program is asking is already quite clearly stated in the opening prompt. I chose two 36 | #to use the split method since words are seperated by a space. This seems like a simple and 37 | #clear way of solving the problem and sets up the string in a useful data type for the later 38 | # objectives. 39 | 40 | 41 | #Side note -- These print statements are used for debugging and making the output more easily 42 | #understood by however is running the program. Hope it helps you too! 43 | 44 | print('\n') 45 | print('The prompt was Objective A & B') 46 | print('\n') 47 | print('Objecive C'+'\n') 48 | 49 | 50 | 51 | # Objective c 52 | for word in word_lst: 53 | print(str(word)) 54 | 55 | #The new line character is automatically adding when using a for loop 56 | 57 | print('\n') 58 | 59 | # Objective d - The 3 is exclusive where as the 0 is inclusive 60 | 61 | print('Objective D'+'\n') 62 | print(word_str[0:3]) 63 | 64 | #I used string parsing with the original string. The 3 is exclusive and the 0 is inclusive. 65 | 66 | print('\n') 67 | 68 | # Objective e 69 | 70 | print('Objective E'+'\n') 71 | print(word_str[-3:]) 72 | 73 | #I used string parsing on the original string again, not saying start from the negative 3 position 74 | 75 | print('\n') 76 | print('Objective F'+'\n') 77 | 78 | # Objective f 79 | first_half = int((len(word_str)/2)) 80 | print(word_str[:first_half]) 81 | 82 | # Using string parsing on the orginal string again, only now calculating the middle of the string 83 | #before parsing. I am including the spaces as part of the string. 84 | 85 | print('\n') 86 | print('Objective G'+'\n') 87 | 88 | # Objective g 89 | last_half = int((len(word_str)/2)) 90 | print(word_str[last_half:]) 91 | 92 | #This is almost the same as the objective above, only where we start and stop has changed 93 | 94 | print('\n') 95 | print('Objective H'+'\n') 96 | 97 | # Objective h 98 | reverse_lst = word_lst[::-1] 99 | for i in reverse_lst: 100 | print(i) 101 | 102 | #I made a new list and used the reverse order syntax --> lst[::-1] and then printed the new list 103 | #with a for loop. 104 | 105 | print('\n') 106 | print('Objective J'+'\n') 107 | 108 | # Objective j 109 | 110 | for word in word_lst: 111 | for char in word: 112 | print(char) 113 | #using a nested loop to loop through each character in each word and printing it to a new line. 114 | #Omitting the spaces, though I could of just of easily used a single for loop to loop through each 115 | #character of the string as well. 116 | 117 | print('\n') 118 | print('Objective K'+'\n') 119 | 120 | # Objective k 121 | for word in word_lst: 122 | for char in word: 123 | print(ord(char)) 124 | 125 | #Using the built in function of ord(), i looped through the list of words and printed out the 126 | #hexidecimal value for each word. Again I could of looped through a list of each character 127 | #and dones the same,though there was some ambiguity as to what was correct and I chose this method. 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /vector_graphics.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | # This is a program that draws an isosceles triangle 5 | # with vector graphics 6 | 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | 10 | # NOTE- These two lines set up two arrays 11 | # pvals is -512 wide for the width of the plot 12 | # -409 high for the heigth of the plot 13 | # -3 cells deep for RGB values 14 | 15 | 16 | #blue is an array that is sets the RGB to blue 17 | pvals = np.ones((512, 409, 3), dtype='uint8')*255 18 | blue = np.array([0,0,255], dtype='unit8') 19 | 20 | 21 | # top-> outer edge 22 | # bottom -> inner edge 23 | 24 | def top_hyp(x): 25 | return((3/4)*x+32) 26 | 27 | def bottom_hyp(x): 28 | return((3/4)*x+2) 29 | 30 | #Conditionals set each pixel blue or it remains white 31 | for i in range(len(pvals)): 32 | for j in range(len(pvals[0])): 33 | if 28 <= i <= 88 and 48 <= j <= top_hyp(i): 34 | pvals[i,j,:] = blue 35 | if 88 < i <= 448 and 48 <= j <= 68: 36 | pvals[i,j,:] = blue 37 | if 448 < i <= 468 and 48 <= j <= top_hyp(i): 38 | pvals[i,j,:] = blue 39 | if 88 < i <= 448 and bottom_hyp(i) <= j <= top_hyp(i): 40 | pvals[i,j,:] = blue 41 | 42 | #rotating the array so it is in the correct orientation 43 | 44 | np.flipud(pvals.transpose(1,0,2)) 45 | p = np.rot90(pvals, 1) 46 | 47 | 48 | f1, ax1 = plt.subplots() 49 | ax1.imshow(p, interpolation='none') 50 | ax1.axis('off') 51 | plt.show() 52 | --------------------------------------------------------------------------------