#!/usr/bin/env python
# coding: utf-8
import re
import subprocess
import shlex
import os
import argparse, sys, collections
import urllib2
import json
import httplib
import time, datetime
# Just server address for all builds, otherwise only for given list of views
# place in jenkins
# get total number of failed builds
# run the job daily
# Create email groups
# Arguments: A. comma separated total number of failed builds - increasing order of builds, B. comma separated email addresses corresponding to the build-number groups
# usage: ./p4_create_user.py user_id manager_id group_id location_id : 4 required arguments
script_objective = '''
Purpose of the script:
Send email to different group of email addresses based on total number of failed builds
'''
# Message display when there are not enough arguments on command line
if len(sys.argv) < 2:
print "Please run the script with argument -h for help"
exit(0)
# argument parsing:
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
add_help=True, description = '', epilog = script_objective)
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-view_urls', nargs = '?', const = '', help = 'Comma separated Jenkins view(s)/server url', required = True)
requiredNamed.add_argument('-build_nums', nargs = '?', const = '', help = 'Comma separated build mumbers for mapping with email groups', required = True)
requiredNamed.add_argument('-emails', nargs = '?', const = '', help = 'Semicolon separated email groups for mapping with build groups. Emails in a group are comma separated', required = True)
args = parser.parse_args()
view_urls = args.view_urls
build_nums = args.build_nums # group = its number or more
emails = args.emails
email_domain = '@ruckuswireless.com'
email_from = 'releng-team' + email_domain
email_to = 'gopal.singh' + email_domain
email_cc = ''
#email_to = email_from
#email_cc = 'releng-team' + email_domain
email_bcc = ''
subject = 'Build failure notification'
email_msg = '''
-Jenkins build failed
'''
jenkins_server = 'http://jenkins.video54.local'
# Jenkins class
INFO = 'api/json'
SCRIPT_OBJECTIVE = '''
Purpose of the script: Detects totals builds, failed builds, and automation failures.
'''
class JenkinsException(Exception): pass
class Jenkins(object):
def __init__(self, url, username=None, password=None):
server_split = (self.fix_server_url(url)).split('/')
self.server = server_split[0] + '//' + server_split[2] + '/'
self.auth = None
def fix_server_url(self, urls): # urls may be comma separated server, view, job, or build urls
url = urls.split(',')[0]
if url[-1] != '/':
url = url + '/'
return url
def fix_urls(self, urls): # urls may be comma separated server, view, job, or build urls
url_str = ''
for url in urls.split(','):
if url[-1] != '/':
url_str += url + '/,'
else:
url_str += url + ','
return url_str.rstrip(',')
def get_jenkins_server_url(self): # extract server url from list of comma separated urls
server_url = (self.server).split('')
return server_url
def jenkins_open(self, req): # req = HTTP request using urllib2
try:
if self.auth:
req.add_header('Authorization', self.auth)
return urllib2.urlopen(req).read()
except urllib2.HTTPError, e:
# Jenkins's funky authentication means its highly impossible to distinguish errors.
if e.code in [401, 403, 500]:
raise JenkinsException('Error in request. Possibly authentication failed [%s]'%(e.code))
def get_info(self, url = None): # get_info gets api/json value for the server url (if server url is provided as jenkinsurl)
if url is None:
url = self.server
try:
return json.loads(self.jenkins_open(urllib2.Request(url + INFO)))
except urllib2.HTTPError:
raise JenkinsException("Error communicating with server[%s]"%url)
except httplib.BadStatusLine:
raise JenkinsException("Error communicating with server[%s]"%url)
except ValueError:
raise JenkinsException("Could not parse JSON info for server[%s]"%url)
except:
raise JenkinsException("Possibly wrong url[%s]"%url)
@staticmethod
def valid_view(info_str): # checks if the given url is a view url and has associated jobs
if 'description' in info_str and 'jobs' in info_str and (len(info_str['jobs']) > 0):
return True
else:
return False
@staticmethod
def valid_job(info_str): # checks if the given url is a job url
if 'builds' in info_str and (len(info_str['builds']) > 0):
return True
else:
return False
@staticmethod
def valid_build(info_str): # checks if the given url is a view url and has associated jobs
if 'number' in info_str:
return True
else:
return False
def get_consecutive_failed_builds_in_job(self, job_url, max_builds_count=None):
jenkins_info = self.get_info(job_url)
builds_list = []
try:
first_build = jenkins_info['firstBuild']['number']
except:
print 'No valid build found: for: ' + job_url
return 0, job_url
last_build = jenkins_info['lastBuild']['number']
build_count = 0
for build_num in reversed(range(first_build, last_build + 1)): # range is reversed to start from the latest build
try:
build_url = job_url + str(build_num) + '/'
jenkins_info = self.get_info(url=build_url)
if jenkins_info['result'] == 'SUCCESS': break
if jenkins_info['result'] == 'FAILURE':
builds_list.append(build_url)
build_count += 1
if max_builds_count is not None and build_count >= max_builds_count:
break
except: continue
return build_count, builds_list
def get_consecutive_failed_builds_in_views(self, urls_list, max_builds_count=None): # the list of view urls should be comma separated string
total_failed_builds = []
list_urls = self.fix_urls(urls_list).split(',')
for url in list_urls:
try:
jenkins_info = self.get_info(url)
except:
print 'Not a valid view: ' + url
continue
if self.valid_view(jenkins_info):
failed_builds = []
for job in jenkins_info['jobs']:
num, urls = self.get_consecutive_failed_builds_in_job(job['url'], max_builds_count)
if num > 0:
failed_builds.append([job['url'], num])
print 'Processing JOB: ' + job['url'] + ' ... Failed Builds: ' + str(num)
total_failed_builds.append({url: failed_builds})
else: continue # continue to process next url if the current one is not a valid view url
return total_failed_builds
def update_email_data(build_data, build_nums, view_urls, emails):
email_data = []
for x in build_data:
job_data = []
for y in x.values()[0]: # x.values()[0] => list of job and corresponding failed builds, i.e.: [[u'http://jenkins.video54.local/job/ML_DAILY_SCG_AUTO_INIT/', 2]]
view_email_groups = select_view_email_groups(x.keys()[0], view_urls, emails) # x.keys()[0] => view_url
view_email_groups = fix_builds_email_group(build_nums, view_email_groups)
email_group = select_email_group(build_nums, view_email_groups, y[1]) # y[1] => number of failed builds for the job y[0]
job_data.append(y + [email_group])
email_data.append({x.keys()[0]:job_data})
return email_data
def runcmd(cmd):
cmd = shlex.split(cmd)
try:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, error = proc.communicate()
return out + error
except:
msg = 'Invalid Command: ' + str(cmd)
print msg
return msg
def parse_buildnums_emails(build_nums, emails):
list_buildnums = build_nums.split(',')
a = [int(x) for x in list_buildnums]
list_emails = emails.split(':')
pair = dict(zip(a, list_emails))
return collections.OrderedDict(sorted(pair.items()))
def parse_views_emails(build_nums, emails):
list_buildnums = build_nums.split(',')
a = [int(x) for x in list_buildnums]
list_emails = emails.split(':')
pair = dict(zip(a, list_emails))
return collections.OrderedDict(sorted(pair.items()))
def select_email_group(build_nums, view_email_groups, failed_builds): # email group will be selected for if number of failed builds >= key
#view_email_groups = fix_builds_email_group(build_nums, view_email_groups)
email_dict = parse_buildnums_emails(build_nums, view_email_groups)
email_group = None
#email_group = email_dict.items()[0][1]
for key, value in email_dict.iteritems():
if failed_builds >= key:
email_group = value
return email_group
def fix_view_email_groups(view_urls, emails):
views = view_urls.split(',')
emails_group = emails.split('|')
for num in range(len(views)):
if num < len(emails_group): # use last provided emails group
if emails_group[num] == '': emails_group[num] = emails_group[num - 1]
else:
emails_group.append(emails_group[num - 1])
return zip(views, emails_group)
def fix_builds_email_group(build_nums, build_email_groups):
build_group = build_nums.split(',')
email_group = build_email_groups.split(':')
for num in range(len(build_group)):
if num < len(email_group): # use last provided emails group
if email_group[num] == '': email_group[num] = email_group[num - 1]
else:
email_group.append(email_group[num - 1])
return ':'.join(email_group)
def select_view_email_groups(view_url, view_urls, emails): # gives view corresponding email groups
pair_list = fix_view_email_groups(view_urls, emails)
view_email_groups = ''
for x in pair_list:
if x[0] == view_url:
view_email_groups = x[1]
return view_email_groups
def get_failed_builds(views_list, build_duration):
pass
def verify_email_address(receivers):
error_message = 'One or more email address is invalid'
valid_emails = []
invalid_emails = []
for email_address in (''.join(receivers.split())).split(','): # Taken care off white spaces in the specified emails list
match = re.match('^[_a-z0-9-\.]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email_address)
if match == None:
invalid_emails += [email_address]
else:
valid_emails += [email_address]
if len(invalid_emails) > 0:
print(error_message)
raise ValueError(error_message)
return valid_emails
def send_email(email_from, email_to, email_subject, email_message, email_cc='', email_bcc=''):
sendmail_location = runcmd('which sendmail').strip() # strip() used to trim line feed
p = os.popen('%s -t' % sendmail_location, 'w')
p.write('From: %s\n' % email_from)
p.write('To: %s\n' % email_to)
if email_cc is not '':
p.write('Cc: %s\n' % email_cc)
if email_bcc is not '':
p.write('Bcc: %s\n' % email_bcc)
p.write('Subject: %s\n' % email_subject)
p.write('\n') # blank line separating headers from body
p.write(email_message)
status = p.close()
if status is None: status = 'OK'
print "Sendmail exit status: ", str(status)
return status
def send_verified_email():
global email_from, email_to, email_cc, email_bcc, email_msg, subject
status = None
# send email
valid_emails_to = ','.join(verify_email_address(email_to)) # sendmail does not need list
# Validate CC and BCC addresses
if email_cc is not '':
valid_emails_cc = ','.join(verify_email_address(email_cc))
else:
valid_emails_cc = ''
if email_bcc is not '':
valid_emails_bcc = ','.join(verify_email_address(email_bcc))
else:
valid_emails_bcc = ''
if len(valid_emails_to) > 0:
send_email(email_from, valid_emails_to, subject, email_msg, email_cc=valid_emails_cc, email_bcc=valid_emails_bcc)
else:
print 'No valid email specified'
status = 'Error'
def complete_email_send():
print '\n' # print line feed for cleaner nessage
status = None
status = get_failed_builds(views_list, build_duration)
if status is None:
status = send_verified_email()
return status
def main():
global build_nums, view_urls, emails, subject, email_msg
jenkins = Jenkins('http://jenkins.video54.local/')
failed_job_data = jenkins.get_consecutive_failed_builds_in_views(view_urls)
email_data = update_email_data(failed_job_data, build_nums, view_urls, emails)
print "Failed job and Email data: " + str(email_data)
for x in email_data:
for y in x.values()[0]:
if y[2] is not None:
email_to = y[2]
email_msg = str(y[1]) + ' continuous builds failed for the job: ' + y[0]
send_verified_email()
else:
print 'No valid email to notify: ' + email_msg
if __name__ == '__main__':
main()
Tuesday, May 31, 2016
Friday, May 27, 2016
python interview questions
https://leetcode.com/problems/range-module/description/
# Sorting technique internals:
- if n elements are iterated n x n with one way comparison (> or <) and swapping, each time at least one element will be sorted - as the comparison is one way, one or some sorted items will be left even though there is numerous swapping. So key is: 1. n x n iteration, 2. one way comparison and swaping
# Worst sorting: iteration = n x n = n^2
a = [5,3,4,2]
for x in range(len(a)):
for y in range(len(a)):
if a[x] < a[y]: swap(a, x, y) # This is dumb logic because it appears a[x] is understood to be fixed, but that is not the case. due to swapping a[x] keep changing during comparison. may be better way to do is store the value of a[x] in another variable if that is intended so.
https://www.codementor.io/python/tutorial/essential-python-interview-questions
https://www.google.com/search?q=python+interview+questions&oq=python+interview+questions&aqs=chrome..69i57j0l5.5566j0j4&sourceid=chrome&ie=UTF-8
# Insertion Sort
http://stackoverflow.com/questions/12755568/python-insertion-sort
http://www.geekviewpoint.com/python/sorting/insertionsort
Basic algorithm: Bubble, Insertion, selection: Bubble is worst than insertion and selection
Efficient Algorithm: quick, heap, merge, binary
# Bubble sort:
# Key is 1. compare immediate two numbers, 2. iterate through all list elements, 3. No need to iterate for already confirmed smallest element in its correct location - so save few iterations
# at the end of all main iterations, all elements are are correct place
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheBubbleSort.html
# In the example below, the sorted element goes to the left and that element is untouched by
decreasing stop value of the range
def bubblesort( A ): # iteration = n(n-1)(n-2)...1 = n!
for i in range( len( A ) ): # ensure iteration for all numbers done
for k in range( len( A ) - 1, i, -1 ): # In every iteration one element from the left gets correct place
if ( A[k] < A[k - 1] ):
swap( A, k, k - 1 ) #
# Even if decereasing, range always leave the last value of the right argument. for decrement, if the arg = 0, the recursion will happen only till one higher value - depending on the step value
def swap(a, x, y):
temp = a[x]
a[x] = a[y]
a[y] = temp
# Insertion Sort: # No swapping
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheInsertionSort.html
#
# Maintain a sorted sublist in each iteration for given elements of a list
# the current item is checked against those in the already sorted sublist
# As we look back into the already sorted sublist, we shift those items that are greater to the right.
# When we reach a smaller item or the end of the sublist, the current item can be inserted.
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.
# insertion sort from end
def insertion_sort_x(ar):
for i in range(len(ar) - 2, -1, -1): # len(ar) - 2 represent last number but one in the list ar
temp = ar[i] # select the element next to the sorted number e
k = i
while k < (len(ar) -1) and temp > ar[k+1]:
ar[k] = ar[k+1]
k += 1
ar[k] = temp
print str(ar)
# Selection sort
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheSelectionSort.html
def selection_sort_x(aList):
for i in range( len( aList ) ):
least = i
for k in range( i + 1 , len( aList ) ):
if aList[k] < aList[least]:
least = k
swap( aList, least, i )
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheQuickSort.html
# Quick sort -1
# Quick sort -2
def quicksort(alis):
_quicksort(alist, 0, len(alist)-1)
def _quicksort(alist, first, last):
if first < last:
splitpoint = partition(alist, first, last)
_quicksort(alist, first, splitpoint-1)
_quicksort(alist, splitpoint+1, last)
def partition(alist, first, last):
pivot = alist[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivot:
leftmark += 1
while rightmark >= leftmark and alist[rightmark] >= pivot:
rightmark -= 1
if rightmark < leftmark:
done = True
else:
swap(alist, leftmark, rightmark)
swap(alist, first, rightmark)
return rightmark
def swap(A, x, y):
A[x],A[y] = A[y], A[x]
alist = [54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)
==========
# 12 hr time to 24 hour time:
t_splt = time.split(':')
if t_splt[2][2:] == 'PM' and t_splt[0] != '12':
t_splt[0] = str(12+ int(t_splt[0]))
elif int(t_splt[0])==12 and t_splt[2][2:] == 'AM':
t_splt[0] = '00'
t_splt[2] = t_splt[2][:2]
print ':'.join(t_splt)
# Fill python list
http://stackoverflow.com/questions/5908420/how-to-fill-a-list-with-0-using-python
# float number precision formatting
"{0:.2f}".format(13.949999999999999) # precision upto 2 decimal place
"{0:.nf}".format(13.949999999999999) # precision upto n decimal place
"{0:>2}h {1:>2}m {2:>2}s".format(hrs, mts, sec) :: first 0, 1, 2 are positional values of hrs, mts, sec
http://stackoverflow.com/questions/20309255/how-to-pad-a-string-to-a-fixed-length-with-spaces-in-python
http://stackoverflow.com/questions/8450472/how-to-format-print-output-into-fixed-width
http://stackoverflow.com/questions/339007/nicest-way-to-pad-zeroes-to-string
'{x:y<z}'.format(p,q,r) :: x = positional variable from format(...): y = fill in character, z = total reserved place for the variable it is associated with: >/< : angle nose is starting point of the reserved
space: > => reservation starts from the right side: < => reservation starts from the leftside
"{0:>2} {1:>2} {2:>2}".format(2, 3, 4)
>>> print '{0:03d}, {1:03d}'.format(1,2) >>> 001, 002
"".ljust()
print 'as %d %s' % (2, 3)
1. 'my name is %s singh' % ('gopal')
2. 'my name is {} singh'.format('gopal')
3. 'my name is {name} singh'.format(name='gopal')
4. 'gopal'.ljust(15)
5. 'gopal'.rjust(15)
6. my name is %(name)s singh'%locals() : When name = 'gopal' is defined
7. '0:.nf'.format(decimal_number) : n = nth number precision of decimal mumbers
8. print '%5s' % 'aa'
# factorial calculation
def factorial(n):return reduce(lambda x,y:x*y,[1]+range(1,n+1))
#
def factorial(number):
if number <= 1: return 1
return number*factorial(number - 1)
print factorial (5)
#
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1) # key technique is factorial(n-1), where n-1 is gets reduced on every recursion compared to factorial(n)
print factorial(4)
# Fibonacci sequence: next sequence is sum of the earlier two numbers
nth Fibonacci
>>> def fib(n):
# Get first two values hard coded as 1,1, .. The rest will be calculated per easy pattern
... a,b = 1,1 # variable 'a' is of interest
... for i in range(n-1): # n-1 max value is selected to exclude 1st and second values: range (n-1) will # exclude nth and (n-1)th numbers from the iteration list
a, b = b, a + b
... return a
...
>>> fib(2)
1
>>> fib(12)
144
#
def fib(n):
a = b = 1
for x in range(n-1):
a, b = b, a + b
print a
fib(6)
#
def fib(n):
f = [1,1]
for x in range(n-2):
s = f[0] + f[1]
f[0] = f[1]
f[1] = s
print s
fib(7)
#
def fib(n):
a = b = 1
for x in range(n-2):
s = a + b
a = b
b = s
print s
fib(7)
# reversed list:
WARNING: reverse() or reversed(list) works unusual way:
-[1,2,3].reverse() returns None and just modified the given list
-reversed([1,2,3]) returns iterable object (not the reversed list)
So, DO NOT use count that reverse() or reversed(list) give a list
Elegant way to reverse a list is using negative step:
def reverse3(nums):
return nums[::-1]
# using lambda, map, filter, reduce: List comprehension is alternative of using lambda, map, filter, reduce. The python creator 'Guido van Rossums prefers using list comprehension
lambda: inline function, no need to use the keyword 'def', no indentation, one liner function, no need to parenthesis, do not need to use the keyword 'return'. It is also used for an expression substitution as in filter.
filter accepts an expression that needs to be true to filter or retrieve only those values for which the given expression is true.
all of map, filter, reduce accepts the argument (function, list). map can accept more than one list.
-map() applies the function func to all the elements of the sequence seq. It returns a new list with the elements changed by func. map can take multiple lists per applied function's number of arguments
-The function filter(function, list) offers an elegant way to filter out all the elements of a list, for which the function function returns True.
map(lambda x: x*x, [1,2,3])
# sum of all elements in a integer list:
def sum3(nums):
return reduce(lambda x, y: x + y, nums)
http://www.secnetix.de/olli/Python/lambda_functions.hawk
http://www.python-course.eu/lambda.php
>>> f = lambda x,y: x + y
>>> f(1,1)
2
output = filter(None, error.split('\n'))
list comprehension: an easy way to create pattern based list.
my_numbers = [x for x in range(5)]
# string formatting:
>>> 'a {2} {0}'.format('1', '2', '3')
'a 3 1'
>>> 'a {} {}'.format('1', '2', '3')
'a 1 2'
# ONE LESS value for range and LIST Splice: range(1,3) => [1,2] :: [1,2,3][:2] => [list[0],list[1]] - then higher index is ONE LESS than the higher argument
# Logical operators: and / or : && and || are not used as is the case with some common languages like C/C++. && => and: || => or
# BitWise operator in python: AND => & : OR => |
# any and all: these operates on a list. all returns true when all element are True or non-empty (non-null). any returns if any element is True, or non-empty(non-null)
# range value: highest value of the list created by range is ONE LESS than the stop argument. range(start, stop, step)
# primary number: 0 and 1 are not primary numbers: a natural number greater than 1, divisible by self and 1 only.
You need to check all numbers from 2 to n-1 (to sqrt(n) actually, but ok, let it be n). If n is divisible by any of the numbers, it is not prime. If a number is prime, print it.
for num in range(1,101): #Need to exclude 1
prime = True
for i in range(2,num):
if (num%i==0):
prime = False
if prime:
print num
>>> def a(n1, n2): #Need to exclude 1
... for n in range(n1, n2+1):
... if all(n%i != 0 for i in range(2, n)): print n
#
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# replace string letter at an index
def missing_char(str, n):
return str.replace(str[n], '')
# check subset
def array123(nums):
return set([1,2,3]).issubset(set(nums))
#
def string_bits(str):
return ''.join([str[x] for x in range(0,len(str),2)])
#
def array_count9(nums):
return len([x for x in nums if x == 9])
# python generators:
https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
yield with respect to coroutines, cooperative multitasking and asynchronous I/O
# matching substring of length 2
def string_match(a, b):
count = 0
shorter = min(len(a), len(b))
for i in range(shorter -1):
if a[i:i+2] == b[i:i+2]: count += 1
return count
# String formatting:
def hello_name(name):
return 'Hello {}!'.format(name)
# Split string
def make_out_word(out, word):
#split the out string in two parts
out1 = out[:2]
out2 = out[2:]
return out1 + word + out2
# Return first half of a string
def first_half(str):
return str[:(len(str))/2]
# list splice from last:
def extra_end(str):
return str[-2:] + str[-2:] + str[-2:]
# rotate string
http://stackoverflow.com/questions/9457832/python-list-rotation
def rotate(l,n):
return l[-n:] + l[:-n]
left: n = +ve
# python ternary operation
http://book.pythontips.com/en/latest/ternary_operators.html
def first_two(str):
return str[:2] if len(str) > 2 else str
#=====
# RangeModule Solution
# Complete the methods below.
class RangeModule:
def __init__(self):
self.range_list = []
def CheckOverlap(self, min2, max2):
overlap_index = -1
counter = 0
for range in self.range_list:
min1 = range[0]
max1 = range[1]
if max(min1, min2) <= min(max1, max2): break
overlap_index += 1
return overlap_index
def CheckContains(self, min2, max2):
contain = False
for range in self.range_list:
min1 = range[0]
max1 = range[1]
if ((min1 <= min2) and (max1 >= max2)):
contain = True
break
return contain
def AddRange(self, lower, upper):
if len(self.range_list) == 0:
self.range_list = [(lower, upper)]
return
if self.CheckContains(lower, upper): pass
overlap_index = self.CheckOverlap(lower, upper)
if overlap_index > -1:
self.range_list[overlap_index][0] = min(self.min, lower)
self.range_list[overlap_index][1] = min(self.min, lower)
else:
self.range_list.append((lower, upper))
def QueryRange(self, lower, upper):
if (lower, upper) in self.range_list: return True
else: return False
def RemoveRange(self, lower, upper):
counter = 0
for range in self.range_list:
# if existing range is contained in the given range
if min(range[0], lower) >= lower and max(range[1], upper) <= upper:
self.range_list.remove(range)
# if given range overlap
if lower >= range[0] and lower <= range[1]:
if upper < range[1]:
self.range_list[counter] = (range[0], lower-1)
self.range_list.append((upper+1, range[1]))
else:
self.range_list[counter] = (range[0], upper-1)
else:
if upper >= range[1]:
self.range_list.remove(range)
else:
self.range_list[counter] = (upper+1, range[1])
counter += 1
rm = RangeModule()
rm.AddRange(10, 100)
print rm.range_list
rm.QueryRange(10, 10)
rm.RemoveRange(25,44)
print rm.range_list
# Fizzbuzz question:
# Fibonacci numbers using generator
# Sorting technique internals:
- if n elements are iterated n x n with one way comparison (> or <) and swapping, each time at least one element will be sorted - as the comparison is one way, one or some sorted items will be left even though there is numerous swapping. So key is: 1. n x n iteration, 2. one way comparison and swaping
# Worst sorting: iteration = n x n = n^2
a = [5,3,4,2]
for x in range(len(a)):
for y in range(len(a)):
if a[x] < a[y]: swap(a, x, y) # This is dumb logic because it appears a[x] is understood to be fixed, but that is not the case. due to swapping a[x] keep changing during comparison. may be better way to do is store the value of a[x] in another variable if that is intended so.
https://www.codementor.io/python/tutorial/essential-python-interview-questions
https://www.google.com/search?q=python+interview+questions&oq=python+interview+questions&aqs=chrome..69i57j0l5.5566j0j4&sourceid=chrome&ie=UTF-8
# Insertion Sort
http://stackoverflow.com/questions/12755568/python-insertion-sort
http://www.geekviewpoint.com/python/sorting/insertionsort
Basic algorithm: Bubble, Insertion, selection: Bubble is worst than insertion and selection
Efficient Algorithm: quick, heap, merge, binary
# Bubble sort:
# Key is 1. compare immediate two numbers, 2. iterate through all list elements, 3. No need to iterate for already confirmed smallest element in its correct location - so save few iterations
# bubble down the smallest number to the left in each iteration and sub iteration
# at the end on first complete iteration, the smallest number bubbles down to the correct place
# at the end on 2nd complete iteration, the next smallest number bubbles down to the correct place
# so in every sub iteration, checking one place less from the left is safe
# at the end of all main iterations, all elements are are correct place
# In the example below, the sorted element goes to the left and that element is untouched by
decreasing stop value of the range
def bubblesort( A ): # iteration = n(n-1)(n-2)...1 = n!
for i in range( len( A ) ): # ensure iteration for all numbers done
for k in range( len( A ) - 1, i, -1 ): # In every iteration one element from the left gets correct place
if ( A[k] < A[k - 1] ):
swap( A, k, k - 1 ) #
# Even if decereasing, range always leave the last value of the right argument. for decrement, if the arg = 0, the recursion will happen only till one higher value - depending on the step value
def swap(a, x, y):
temp = a[x]
a[x] = a[y]
a[y] = temp
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheInsertionSort.html
#
# Maintain a sorted sublist in each iteration for given elements of a list
# the current item is checked against those in the already sorted sublist
# As we look back into the already sorted sublist, we shift those items that are greater to the right.
# When we reach a smaller item or the end of the sublist, the current item can be inserted.
Approach:
# Insertion sort is good for collections that are very small
# or nearly sorted. Otherwise it's not a good sorting algorithm:
# it moves data around too much. Each time an insertion is made,
# all elements in a greater position are shifted.
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.
def
insertionsort( aList ):
for i in range( 1, len( aList ) ):
tmp = aList[i] # Current element
k = i
while k > 0 and tmp < aList[k - 1]: # do sorting on the sorted list
aList[k] = aList[k - 1]
k -= 1
aList[k] = tmp # k will be reduced to one less when while loop will break or at least
# will be initialized to same number ; equivalent to no change
# insertion sort from end
def insertion_sort_x(ar):
for i in range(len(ar) - 2, -1, -1): # len(ar) - 2 represent last number but one in the list ar
temp = ar[i] # select the element next to the sorted number e
k = i
while k < (len(ar) -1) and temp > ar[k+1]:
ar[k] = ar[k+1]
k += 1
ar[k] = temp
print str(ar)
# Selection sort
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheSelectionSort.html
def selection_sort_x(aList):
for i in range( len( aList ) ):
least = i
for k in range( i + 1 , len( aList ) ):
if aList[k] < aList[least]:
least = k
swap( aList, least, i )
http://interactivepython.org/runestone/static/pythonds/SortSearch/TheQuickSort.html
# Quick sort -1
import
random
def
quicksort( aList ):
_quicksort( aList,
0
,
len
( aList )
-
1
)
def
_quicksort( aList, first, last ):
if
first < last:
pivot
=
partition( aList, first, last )
_quicksort( aList, first, pivot
-
1
)
_quicksort( aList, pivot
+
1
, last )
def
partition( aList, first, last ) :
pivot
=
first
+
random.randrange( last
-
first
+
1
)
swap( aList, pivot, last )
for
i
in
range
( first, last ):
if
aList[i] <
=
aList[last]:
swap( aList, i, first )
first
+
=
1
swap( aList, first, last )
return
first
def
swap( A, x, y ):
A[x],A[y]
=
A[y],A[x]
# Quick sort -2
def quicksort(alis):
_quicksort(alist, 0, len(alist)-1)
def _quicksort(alist, first, last):
if first < last:
splitpoint = partition(alist, first, last)
_quicksort(alist, first, splitpoint-1)
_quicksort(alist, splitpoint+1, last)
def partition(alist, first, last):
pivot = alist[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivot:
leftmark += 1
while rightmark >= leftmark and alist[rightmark] >= pivot:
rightmark -= 1
if rightmark < leftmark:
done = True
else:
swap(alist, leftmark, rightmark)
swap(alist, first, rightmark)
return rightmark
def swap(A, x, y):
A[x],A[y] = A[y], A[x]
alist = [54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)
==========
# 12 hr time to 24 hour time:
t_splt = time.split(':')
if t_splt[2][2:] == 'PM' and t_splt[0] != '12':
t_splt[0] = str(12+ int(t_splt[0]))
elif int(t_splt[0])==12 and t_splt[2][2:] == 'AM':
t_splt[0] = '00'
t_splt[2] = t_splt[2][:2]
print ':'.join(t_splt)
# Fill python list
http://stackoverflow.com/questions/5908420/how-to-fill-a-list-with-0-using-python
# float number precision formatting
"{0:.2f}".format(13.949999999999999) # precision upto 2 decimal place
"{0:.nf}".format(13.949999999999999) # precision upto n decimal place
"{0:>2}h {1:>2}m {2:>2}s".format(hrs, mts, sec) :: first 0, 1, 2 are positional values of hrs, mts, sec
print '%5s' % 'aa'
http://stackoverflow.com/questions/20309255/how-to-pad-a-string-to-a-fixed-length-with-spaces-in-python
http://stackoverflow.com/questions/8450472/how-to-format-print-output-into-fixed-width
http://stackoverflow.com/questions/339007/nicest-way-to-pad-zeroes-to-string
'{x:y<z}'.format(p,q,r) :: x = positional variable from format(...): y = fill in character, z = total reserved place for the variable it is associated with: >/< : angle nose is starting point of the reserved
space: > => reservation starts from the right side: < => reservation starts from the leftside
"{0:>2} {1:>2} {2:>2}".format(2, 3, 4)
"{0} {1} {2}".format(2, 3, 4) :: 0,1,2 are positional variables
>>> "{:0>2}".format("1") # Works for both numbers and strings.
'01'
>>> "{:02}".format(1) # Only works for numbers.
'01'
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005
>>> print '{0:03d}, {1:03d}'.format(1,2) >>> 001, 002
"".ljust()
>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
>>> n = 4
>>> print '%03d' % n
>>> 004
>>> print format(4, '03') # python >= 2.6
>>> 004
>>> print '{0:03d}'.format(4) # python >= 2.6
>>> 004
>>> print('{0:03d}'.format(4)) # python 3
>>> 004
>>> n = '4'
>>> print n.zfill(3)
>>> '004'
>>> name = 'John'
>>> name.ljust(15)
'John '
>>> a = "John"
>>> "{:<15}".format(a)
'John '
"The {structure} sank {0} times in {1} years.".format( ... 3, 2, structure='castle') 'The castle sank 3 times in 2 years.'
print 'as %d %s' % (2, 3)
print "A list: %s" % mylist
%s - String (or any object with a string representation, like numbers)
%d - Integers
%f - Floating point numbers
%.<number of digits>f - Floating point numbers with a fixed amount of digits to the right of the dot.
%x/%X - Integers in hex representation (lowercase/uppercase)
key formatting:1. 'my name is %s singh' % ('gopal')
2. 'my name is {} singh'.format('gopal')
3. 'my name is {name} singh'.format(name='gopal')
4. 'gopal'.ljust(15)
5. 'gopal'.rjust(15)
6. my name is %(name)s singh'%locals() : When name = 'gopal' is defined
7. '0:.nf'.format(decimal_number) : n = nth number precision of decimal mumbers
8. print '%5s' % 'aa'
# factorial calculation
def factorial(n):return reduce(lambda x,y:x*y,[1]+range(1,n+1))
#
def factorial(number):
if number <= 1: return 1
return number*factorial(number - 1)
print factorial (5)
#
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1) # key technique is factorial(n-1), where n-1 is gets reduced on every recursion compared to factorial(n)
print factorial(4)
# Fibonacci sequence: next sequence is sum of the earlier two numbers
nth Fibonacci
>>> def fib(n):
# Get first two values hard coded as 1,1, .. The rest will be calculated per easy pattern
... a,b = 1,1 # variable 'a' is of interest
... for i in range(n-1): # n-1 max value is selected to exclude 1st and second values: range (n-1) will # exclude nth and (n-1)th numbers from the iteration list
a, b = b, a + b
... return a
...
>>> fib(2)
1
>>> fib(12)
144
#
def fib(n):
a = b = 1
for x in range(n-1):
a, b = b, a + b
print a
fib(6)
#
def fib(n):
f = [1,1]
for x in range(n-2):
s = f[0] + f[1]
f[0] = f[1]
f[1] = s
print s
fib(7)
#
a = b = 1
for x in range(n-2):
s = a + b
a = b
b = s
print s
fib(7)
# reversed list:
WARNING: reverse() or reversed(list) works unusual way:
-[1,2,3].reverse() returns None and just modified the given list
-reversed([1,2,3]) returns iterable object (not the reversed list)
So, DO NOT use count that reverse() or reversed(list) give a list
Elegant way to reverse a list is using negative step:
def reverse3(nums):
return nums[::-1]
# using lambda, map, filter, reduce: List comprehension is alternative of using lambda, map, filter, reduce. The python creator 'Guido van Rossums prefers using list comprehension
lambda: inline function, no need to use the keyword 'def', no indentation, one liner function, no need to parenthesis, do not need to use the keyword 'return'. It is also used for an expression substitution as in filter.
filter accepts an expression that needs to be true to filter or retrieve only those values for which the given expression is true.
all of map, filter, reduce accepts the argument (function, list). map can accept more than one list.
-map() applies the function func to all the elements of the sequence seq. It returns a new list with the elements changed by func. map can take multiple lists per applied function's number of arguments
-The function filter(function, list) offers an elegant way to filter out all the elements of a list, for which the function function returns True.
-The function reduce(func, seq) continually applies the function func() to the sequence seq. It returns a single value.
map(lambda x: x*x, [1,2,3])
>>> def a(x, y):
... return 5
>>> map(a, [1,2,3], [1,2,3,4])
>>> filter(None, [1,2,3, '', None])
[1, 2, 3]
#Calculating the sum of the numbers from 1 to 100:
>>> reduce(lambda x, y: x+y, range(1,101))
5050
>>> reduce(lambda x, y: x+y, range(1,101))
5050
# sum of all elements in a integer list:
def sum3(nums):
return reduce(lambda x, y: x + y, nums)
http://www.secnetix.de/olli/Python/lambda_functions.hawk
http://www.python-course.eu/lambda.php
>>> f = lambda x,y: x + y
>>> f(1,1)
2
>>> def make_incrementor (n): return lambda x: x + n
>>>
>>> f = make_incrementor(2)
>>> g = make_incrementor(6)
>>>
>>> print f(42), g(42)
44 48
>>>
>>> print make_incrementor(22)(33)
55
output = filter(None, error.split('\n'))
list comprehension: an easy way to create pattern based list.
my_numbers = [x for x in range(5)]
# string formatting:
>>> 'a {2} {0}'.format('1', '2', '3')
'a 3 1'
>>> 'a {} {}'.format('1', '2', '3')
'a 1 2'
str_heading = "{ts:12}, {name:50},{q:<15},{b:<15},{t:<15}".format(ts='Date', name='Description.number', q='Waiting', b='Building', t='Total time')
str_heading_html = "{ts:23} {name:50}{q:<15}{b:<15}{t:<15}".format(ts='\n<tr><td>Date', name=' </td><td>Description.number', q='</td><td>Waiting', b='</td><td>Building', t='</td><td>Total time</td></tr>')
def format_time (msTime):
sec = msTime / 1000
mts, sec = divmod(sec, 60)
hrs, mts = divmod(mts, 60)
if hrs > 0:
return "{0:>2}h {1:>2}m {2:>2}s".format(hrs, mts, sec)
elif mts >0:
return "{0:>2}m {1:>2}s".format(mts, sec)
else:
return "{0:>2}s".format(sec)
# ONE LESS value for range and LIST Splice: range(1,3) => [1,2] :: [1,2,3][:2] => [list[0],list[1]] - then higher index is ONE LESS than the higher argument
# Logical operators: and / or : && and || are not used as is the case with some common languages like C/C++. && => and: || => or
# BitWise operator in python: AND => & : OR => |
# any and all: these operates on a list. all returns true when all element are True or non-empty (non-null). any returns if any element is True, or non-empty(non-null)
# range value: highest value of the list created by range is ONE LESS than the stop argument. range(start, stop, step)
# primary number: 0 and 1 are not primary numbers: a natural number greater than 1, divisible by self and 1 only.
You need to check all numbers from 2 to n-1 (to sqrt(n) actually, but ok, let it be n). If n is divisible by any of the numbers, it is not prime. If a number is prime, print it.
for num in range(1,101): #Need to exclude 1
prime = True
for i in range(2,num):
if (num%i==0):
prime = False
if prime:
print num
>>> def a(n1, n2): #Need to exclude 1
... for n in range(n1, n2+1):
... if all(n%i != 0 for i in range(2, n)): print n
# Optimized by using square root:
import math
>>>
import math
for num in range(1,101):
if all(num%i!=0 for i in range(2,int(math.sqrt(num))+1)):
print num
>>>
import math
for num in range(1,101):
if all(num%i!=0 for i in range(2,int(math.sqrt(num))+1)):
print num
#
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# replace string letter at an index
def missing_char(str, n):
return str.replace(str[n], '')
# check subset
def array123(nums):
return set([1,2,3]).issubset(set(nums))
#
def string_bits(str):
return ''.join([str[x] for x in range(0,len(str),2)])
#
def array_count9(nums):
return len([x for x in nums if x == 9])
# python generators:
https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
yield with respect to coroutines, cooperative multitasking and asynchronous I/O
# matching substring of length 2
def string_match(a, b):
count = 0
shorter = min(len(a), len(b))
for i in range(shorter -1):
if a[i:i+2] == b[i:i+2]: count += 1
return count
# String formatting:
def hello_name(name):
return 'Hello {}!'.format(name)
# Split string
def make_out_word(out, word):
#split the out string in two parts
out1 = out[:2]
out2 = out[2:]
return out1 + word + out2
# Return first half of a string
def first_half(str):
return str[:(len(str))/2]
# list splice from last:
def extra_end(str):
return str[-2:] + str[-2:] + str[-2:]
# rotate string
http://stackoverflow.com/questions/9457832/python-list-rotation
def rotate(l,n):
return l[-n:] + l[:-n]
left: n = +ve
# python ternary operation
http://book.pythontips.com/en/latest/ternary_operators.html
def first_two(str):
return str[:2] if len(str) > 2 else str
#=====
# RangeModule Solution
# Complete the methods below.
class RangeModule:
def __init__(self):
self.range_list = []
def CheckOverlap(self, min2, max2):
overlap_index = -1
counter = 0
for range in self.range_list:
min1 = range[0]
max1 = range[1]
if max(min1, min2) <= min(max1, max2): break
overlap_index += 1
return overlap_index
def CheckContains(self, min2, max2):
contain = False
for range in self.range_list:
min1 = range[0]
max1 = range[1]
if ((min1 <= min2) and (max1 >= max2)):
contain = True
break
return contain
def AddRange(self, lower, upper):
if len(self.range_list) == 0:
self.range_list = [(lower, upper)]
return
if self.CheckContains(lower, upper): pass
overlap_index = self.CheckOverlap(lower, upper)
if overlap_index > -1:
self.range_list[overlap_index][0] = min(self.min, lower)
self.range_list[overlap_index][1] = min(self.min, lower)
else:
self.range_list.append((lower, upper))
def QueryRange(self, lower, upper):
if (lower, upper) in self.range_list: return True
else: return False
def RemoveRange(self, lower, upper):
counter = 0
for range in self.range_list:
# if existing range is contained in the given range
if min(range[0], lower) >= lower and max(range[1], upper) <= upper:
self.range_list.remove(range)
# if given range overlap
if lower >= range[0] and lower <= range[1]:
if upper < range[1]:
self.range_list[counter] = (range[0], lower-1)
self.range_list.append((upper+1, range[1]))
else:
self.range_list[counter] = (range[0], upper-1)
else:
if upper >= range[1]:
self.range_list.remove(range)
else:
self.range_list[counter] = (upper+1, range[1])
counter += 1
rm = RangeModule()
rm.AddRange(10, 100)
print rm.range_list
rm.QueryRange(10, 10)
rm.RemoveRange(25,44)
print rm.range_list
# Fizzbuzz question:
# Fibonacci numbers using generator
#! /usr/bin/env python
def fibo(number):
a,b = 1,1
for i in xrange(number):
a,b = b, a + b
yield b
for item in fibo(10): print item
# RangeModule-2
# RangeModule
# addRange[left, right)
# queryRange[left, right)
# removeRange[left, right)
class RangeModule(object):
def __init__(self, rmrange=[]):
self.rmrange = rmrange
def get_range(self):
return self.rmrange
def set_range(self, rmrange):
self.rmrange = rmrange
def addRange(self, left, right):
self.rmrange += range(left, right)
self.rmrange = list(set(self.rmrange)) #.sort()
def queryRange(self, left, right):
l1 = range(left, right)
l1.sort()
l2 = self.rmrange
l2.sort()
if len(set(l1) & set(l2)) >= len(l1): return True
else: return False
def deleteRange(self, left, right):
self.rmrange = list(set(self.rmrange).difference(set(range(left, right))))
rm = RangeModule()
rm.addRange(1,10)
rm.addRange(1,3)
#rm.addRange(1,3)
print rm.rmrange
rm.deleteRange(2, 4)
rm.deleteRange(2, 5)
print rm.rmrange
print rm.queryRange(5,7)
# Linked List:
- It is a list of node object : a node object has two items - data & points to next node object
# RangeModule-2
# RangeModule
# addRange[left, right)
# queryRange[left, right)
# removeRange[left, right)
class RangeModule(object):
def __init__(self, rmrange=[]):
self.rmrange = rmrange
def get_range(self):
return self.rmrange
def set_range(self, rmrange):
self.rmrange = rmrange
def addRange(self, left, right):
self.rmrange += range(left, right)
self.rmrange = list(set(self.rmrange)) #.sort()
def queryRange(self, left, right):
l1 = range(left, right)
l1.sort()
l2 = self.rmrange
l2.sort()
if len(set(l1) & set(l2)) >= len(l1): return True
else: return False
def deleteRange(self, left, right):
self.rmrange = list(set(self.rmrange).difference(set(range(left, right))))
rm = RangeModule()
rm.addRange(1,10)
rm.addRange(1,3)
#rm.addRange(1,3)
print rm.rmrange
rm.deleteRange(2, 4)
rm.deleteRange(2, 5)
print rm.rmrange
print rm.queryRange(5,7)
# Linked List:
- It is a list of node object : a node object has two items - data & points to next node object
Subscribe to:
Posts (Atom)