Feb-18-2019, 02:17 PM
(This post was last modified: Feb-18-2019, 02:17 PM by TheFluffyOne.)
As a long-time Perl coder, I've picked up loads of optimisations and style tips that make scripts easier to understand, shorter, and more efficient.
I occasionally dabble in Python and typically end up brute-forcing some code together using the basic Python capabilities, often thinking how I'd write the script in Perl and then working out the Python equivalent methods. I recently wrote a script to reverse-engineer sample sizes from published percentages, and I suspect it's particularly bad since I directly translated some JavaScript into Python for one of the key functions.
If anyone is able to offer advice on how to improve the script and make it more optimised and Pythonic, I'd be very grateful! I'm working with Python 3.7 simply because it's recent, and not because of any particular attachment to Python 3 over Python 2.
I occasionally dabble in Python and typically end up brute-forcing some code together using the basic Python capabilities, often thinking how I'd write the script in Perl and then working out the Python equivalent methods. I recently wrote a script to reverse-engineer sample sizes from published percentages, and I suspect it's particularly bad since I directly translated some JavaScript into Python for one of the key functions.
If anyone is able to offer advice on how to improve the script and make it more optimised and Pythonic, I'd be very grateful! I'm working with Python 3.7 simply because it's recent, and not because of any particular attachment to Python 3 over Python 2.
# Determine minimum likely values based on provided percentages import math digit_accuracy = 2 results = {} #percentages = [ 4.71, 20.00, 42.35, 32.94 ] percentages = [ 8.57, 5.71, 2.86, 20.00, 14.29, 17.14, 20.00, 5.71, 5.71 ] # Calculate Greatest Common Divisor of two numbers # Based on code from https://www.programiz.com/python-programming/examples/lcm def gcd(x, y): while(y): x, y = y, x % y return x # Calculate Least Common Multiple of two numbers # Based on code from https://www.programiz.com/python-programming/examples/lcm def lcm(x, y): return ((x * y) // gcd(x, y)) # Use continued fraction method to calculate simplest fraction that represents provided decimal at given precision (decimal places) # Based on the JavaScript version at http://jonisalonen.com/2012/converting-decimal-numbers-to-ratios/ def estimate_fraction(decimal_value, decimal_precision): #print("Estimating fractions for", decimal_value) desired_result = round(decimal_value * 100, decimal_precision) h1 = 1 h2 = 0 k1 = 0 k2 = 1 b = decimal_value while True: a = math.floor(b) aux = h1 h1 = (a * h1) + h2 h2 = aux aux = k1 k1 = (a * k1) + k2 k2 = aux rounded_result = round(((h1 * 100) / k1), decimal_precision) if (rounded_result == desired_result): break b = 1 / (b - a) return [h1, k1] # ------------------- MAIN ------------------- def main(): lowest_denominator = 0 for item in percentages: # Find a fraction to estimate the current percentage to the given number of decimal places accuracy [numerator, denominator] = estimate_fraction((item / 100), digit_accuracy) results[item] = [numerator, denominator] # Find the lowest common multiple for the fraction denominators up to this point if (lowest_denominator == 0): lowest_denominator = denominator else: lowest_denominator = lcm(denominator, lowest_denominator) running_total = 0 for x in percentages: [numerator, denominator] = results[x] # Convert all fractions to a common denominator (which should be the sample size) if (denominator != lowest_denominator): multiplier = lowest_denominator / denominator numerator *= multiplier denominator *= multiplier running_total += numerator # Display summary of the calculated values for this entry calculated_percentage = round(((numerator * 100) / denominator), digit_accuracy) print(int(numerator), " / ", int(denominator), " = ", calculated_percentage, "% (Requested: ", x, "%)", sep="") # Print some summary information to help determine if the estimated sample size is sensible print("\nTotal", int(running_total), "items represented of", lowest_denominator) print("Percentages sum to ", round(sum(percentages), digit_accuracy), "%", sep="") # ---------- ENTRY POINT ---------- if __name__ == '__main__': main()