How can I fix this Pythagorean Triplet program? - python

import sys
def pythTrue(a,b,c):
(A,B,C) = (a*a,b*b,c*c)
if A + B == C or B + C == A or A + C == B:
return True
def smallestTrip(a,b,c):
if pythTrue(a,b,c) == True:
if (a+b+c)%12 == 0:
return True
else:
return False
def tuplePyth(n):
list_=[]
for x in range(1, n):
for y in range(1, n):
for z in range (1, n):
if x+y+z<=n:
if smallestTrip(x, y, z)==False:
list_.append([x,y,z])
print (list_)
tuplePyth(int(sys.argv[1]))
Pythagorean triplets are sets of 3 positive integers a, b, c
satisfying the relationship a2 + b2 =
c2. The smallest and best-known Pythagorean triple is
(a, b, c) = (3, 4, 5). Write a program that reads a command line
argument n and prints to the screen all Pythagorean triplets whose sum
is less than n (i.e., a+b+c < n) and that are not multiple of the (3,
4, 5) triplet. Your program will represent triplets as 3-tuples, and
should consist of three functions:
a function that takes in a tuple
and returns a boolean indicating whether the Pythagorean relationship holds or not.
a function that takes in a tuple and returns
a boolean indicating whether a triplet is a multiple of the smallest
triplet or not.
a function that takes in an integer n and generates
the Pythagorean triplets as specified above. The function should
return a list of tuples.
The main portion of your program pythagore.py will read in the command
line input, call the last function described above, and print the
results one triplet per line.
My problem is that I am getting the same combination in different
orders for example: (5,12,13),(13,12,5)...etc

You're short on logic in your main routine. There is nothing to enforce that the triple comes in only one order: your x and y are interchangeable, and you guarantee that you'll check both.
Instead, force x < y with your loop limits, and then make sure you stop when the value of y or z gets too large to be viable. Note that this gets rid of your check for the sum of the three.
def tuplePyth(n):
list_=[]
for x in range(1, n):
for y in range(1, n):
for z in range (1, n):
if x+y+z<=n:
if smallestTrip(x, y, z)==False:
list_.append([x,y,z])
print (list_)
Instead:
def tuplePyth(n):
list_=[]
for x in range(1, n):
for y in range(x + 1, (n - x) // 2):
for z in range (y + 1, n - x - y):
if smallestTrip(x, y, z)==False:
list_.append([x,y,z])
print (list_)
Output with n=100:
[[5, 12, 13], [7, 24, 25], [8, 15, 17], [9, 40, 41], [15, 36, 39], [16, 30, 34], [20, 21, 29]]
Note that you still have a problem with smallestTrip: your check is not logically equivalent to "smallest triple". Instead, check that the three numbers are relatively prime. Since Stack Overflow allows only one question per posting, and the problem is readily researched on line, I'll leave that as an exercise for the student. :-)

An easy solution would be to keep track of the ones aleady found and add checks to avoid repeating them. The following uses a set to store the ones already produced and sorts the the elements in each triple so that their order doesn't matter.
def tuplePyth(n):
list_=[]
seen = set()
for x in range(1, n):
for y in range(1, n):
for z in range (1, n):
if tuple(sorted((x,y,z))) not in seen:
if x+y+z <= n:
if smallestTrip(x, y, z) == False:
list_.append([x,y,z])
seen.add((x,y,z))
print (list_)

You can use itertools:
import itertools.combinations_with_replacement as cwr
list_ = [triple for triple in cwr(range(n),3) if sum(triple)<n and not smallestTrip(triple)]
You can also force the numbers to be in order with the limits. Also, you can simplify finding a,b, c by realizing that if we define a to be the smallest number, then it must be smaller than n/3 (b and c will both be at least as large as a, so if a were larger than n/3, then the sum of a, b, and c would be more than n). Similarly, b must be smaller than n/2. Once you've found all the combinations of a and b, you can find all the c that are larger than b and smaller than n-a-b.
list_=[]
for x in range(1, n//3):
for y in range(x+1, n//2):
for z in range (x+y+1, n-x-y):
if not smallestTrip(x, y, z):
list_.append([x,y,z])

Because the three numbers are never the same you can just change the second and the third range from (1,n) to (x+1,n) and (y+1,n) correspondingly.

Related

Find elements in a list of which all elements in another list are factors, using a list comprehension

I have a list of numbers from which I have extracted common factors of all these numbers. For example, from list b = [16, 32, 96], I have produced list_of_common_factors = [1, 8, 16, 2, 4].
I have another list of integers, a and I wish to extract the numbers from list_of_common_factors of which all elements of a are factors. So if a = [2, 4], then I should end up with [4, 8, 16], as these are the numbers in list_of_common_factors of which 2 and 4 are factors.
However, I am struggling to figure out how to implement this step in a list comprehension, even in pseudocode. It should look something like this: [x for x in list_of_common_factors if all elements of a are factors of x]. It's the if statement that I'm having trouble with because I believe it should contain a for loop, but I can't think of a concise way to write it.
I have managed to do it the long way, using a nested for loop and it looks like this:
between_two_lists = []
# Determine the factors in list_of_common_factors of which all elements of a are factors.
for factor in list_of_common_factors:
# Check that all a[i] are factors of factor.
""" Create a counter.
For each factor, find whether a[i] is a factor of factor.
Do this with a for loop up to len(a).
If a[i] is a factor of factor, then increment the counter by 1.
At the end of this for loop, check if the counter is equal to len(a).
If they are equal to each other, then factor satisfies the problem requirements.
Add factor to between_two_lists. """
counter = 0
for element in a:
if factor % element == 0:
counter += 1
if counter == len(a):
between_two_lists.append(factor)
between_two_lists is the list I am trying to produce by converting the above code into a list comprehension. How can I do that, if it is even possible?
It is what you are looking for:
[x for x in list_of_common_factors if all(x % i==0 for i in a)]
So basically, you need to have a function returning the factors from a list of numbers. This function would return a list. And then you simply need to find the intersection of both list. Since each factor is unique, I suggest to use a set implementation which will be more efficient. To resume, the code would look like:
A = set(factors(#Input 1))
B = set(factors(#Input 2))
N = A.intersection(B)
It might be more efficient to calculate the least common multiple of the elements of a first, especially if a has more than 2 elements:
from functools import reduce
def gcd(x, y): # greatest common divisor
while y:
x, y = y, x % y
return x
def lcm(x, y): # least common multiple
return (x*y)//gcd(x,y)
lcm_of_a = reduce(lcm, a)
result = [x for x in list_of_common_factors if (x % lcm_of_a == 0)]

Finding two integers that multiply to 20. Can I make this code more "pythonic"?

I did this code that finds two integers in a said list (in this case [2,4,5,1,6,40,-1]) that multiply to twenty. I got a little stuck in the beginning, but adding a function to it solved my problems. I showed this code to a friend of mine who's a programmer and he said I could make this code more "pythonic", but I have no clue how.
Here's the code:
num_list = [2,4,5,1,6,40,-1]
def get_mult_num(given_list):
for i in given_list:
for j in range(i+1, len(given_list)): #for j not to be == i and to be in the list
mult_two_numbers = i * j
if mult_two_numbers == 20:
return i,j
print(get_mult_num(num_list))
I don't necessarily think it is 'unpythonic', you are using standard Python idioms to loop over your data and produce a single result or None. The term Pythonic is nebulous, a subject marred in "I know it when I see it" parameters.
Not that you produced a correct implementation. While i loops over given_numbers, j loops over an integer from i + 2 through to len(given_numbers), mixing values from given_list with indices? For your sample input, you are taking j from the half-open ranges [4, 7), [6, 7), [7, 7) (empty), [3, 7), [8, 7) (empty), [42, 7) (empty) and [1, 7), respectively. That it produces the correct answer at all is luck, not due to correctness; if you give your function the list [2, 10], it'll not find a solution! You want to loop over given_numbers again, limited with slicing, or generate indices starting at the current index of i, but then your outer loop needs to add a enumerate() call too:
for ii, i in enumerate(given_numbers):
for j in given_numbers[ii + 1:]:
# ...
or
for ii, i in enumerate(given_numbers):
for jj in range(ii + 1, len(given_numbers)):
j = given_numbers[jj]
# ...
All this is not nearly as efficient as it can be; the Python standard library offers you the tools to generate your i, j pairs without a nested for loop or slicing or other forms of filtering.
Your double loop should generate combinations of the integer inputs, so use the itertools.combinations() object to generate unique i, j pairs:
from itertools import combinations
def get_mult_num(given_list):
return [(i, j) for i, j in combinations(given_list, 2) if i * j == 20]
This assumes there can be zero or more such solutions, not just a single solution.
If you only ever need the first result or None, you can use the next() function:
def get_mult_num(given_list):
multiplies_to_20 = (
(i, j) for i, j in combinations(given_list, 2)
if i * j == 20)
return next(multiplies_to_20, None)
Next, rather than produce all possible combinations, you may want to invert the problem. If you turn given_list into a set, you can trivially check if the target number 20 can be divided cleanly without remainder by any of your given numbers and where the result of the division is larger and is also an integer in the set of numbers. That gives you an answer in linear time.
You can further limit the search by dividing with numbers smaller than the square root of the target value, because you won't find a larger value to match in your input numbers (given a number n and it's square root s, by definition s * (s + 1) is going to be larger than n).
If we add an argument for the target number to the function and make it a generator function, then you get:
def gen_factors_for(target, numbers):
possible_j = set(numbers)
limit = abs(target) ** 0.5
for i in numbers:
if abs(i) < limit and target % i == 0:
j = target // i
if j in possible_j and abs(j) > abs(i):
yield i, j
This approach is a lot faster than testing all permutations, especially if you need to find all possible factors. Note that I made both functions generators here to even out the comparisons:
>>> import random, operator
>>> from timeit import Timer
>>> def gen_factors_for_division(target, numbers):
... possible_j = set(numbers)
... limit = abs(target) ** 0.5
... for i in numbers:
... if abs(i) < limit and target % i == 0:
... j = target // i
... if j in possible_j and abs(j) > abs(i):
... yield i, j
...
>>> def gen_factors_for_combinations(target, given_list):
... return ((i, j) for i, j in combinations(given_list, 2) if i * j == target)
...
>>> numbers = [random.randint(-10000, 10000) for _ in range(100)]
>>> targets = [operator.mul(*random.sample(set(numbers), 2)) for _ in range(5)]
>>> targets += [t + random.randint(1, 100) for t in targets] # add likely-to-be-unsolvable numbers
>>> for (label, t) in (('first match:', 'next({}, None)'), ('all matches:', 'list({})')):
... print(label)
... for f in (gen_factors_for_division, gen_factors_for_combinations):
... test = t.format('f(t, n)')
... timer = Timer(
... f"[{test} for t in ts]",
... 'from __main__ import targets as ts, numbers as n, f')
... count, total = timer.autorange()
... print(f"{f.__name__:>30}: {total / count * 1000:8.3f}ms")
...
first match:
gen_factors_for_division: 0.219ms
gen_factors_for_combinations: 4.664ms
all matches:
gen_factors_for_division: 0.259ms
gen_factors_for_combinations: 3.326ms
Note that I generate 10 different random targets, to try to avoid a lucky best-case-scenario hit for either approach.
[(i,j) for i in num_list for j in num_list if i<j and i*j==20]
This is my take on it, which uses enumerate:
def get_mult_num(given_list):
return [
item1, item2
for i, item1 in enumerate(given_list)
for item2 in given_list[:i]
if item1*item2 == 20
]
I think your friend may be hinting towards using comprehensions when it makes the code cleaner (sometimes it doesn't).
I can think of using list-comprehension. This also helps to find multiple such-pairs if they exist in the given list.
num_list = [2,4,5,1,6,40,-1]
mult_num = [(num_list[i],num_list[j]) for i in range(len(num_list)) for j in range(i+1, len(num_list)) if num_list[i]*num_list[j] == 20]
print mult_num
Output:
[(4, 5)]
I came up with this. It reverses the approach a little bit, in that it searches in num_list for the required pair partner that the iteration value val would multiply to 20 with. This makes the code easier and needs no imports, even if it's not the most efficient way.
for val in num_list:
if 20 / val in num_list:
print(val, int(20/val))
You could make it more pythonic by using itertools.combinations, instead of nested loops, to find all pairs of numbers. Not always, but often iterating over indices as in for i in range(len(L)): is less pythonic than directly iterating over values as in for v in L:.
Python also allows you to make your function into a generator via the yield keyword so that instead of just returning the first pair that multiplies to 20, you get every pair that does by iterating over the function call.
import itertools
def factors(x, numbers):
""" Generate all pairs in list of numbers that multiply to x.
"""
for a, b in itertools.combinations(numbers, 2):
if a * b == x:
yield (a, b)
numbers = [2, 4, 5, 1, 6, 40, -1]
for pair in factors(20, numbers):
print(pair)

form the largest number possible in a list [duplicate]

This question already has answers here:
Sort a list to form the largest possible number
(9 answers)
Closed 4 years ago.
Given a list such as:
[3, 30, 34, 5, 9].
Output: 9534330
Write a program to return the largest number possible
In my code I have used permutation here:
from itertools import permutations
x = [3, 30, 34, 5, 9]
y = permutations(x)
n = len(y)
e = []
for i in y:
a = map(str, i)
e.append(int("".join(i)))
print "Largest Number {}".format(sorted(e)[-1])
Here n which is the length of the number of permutations is 120 because of 5!.
Is there a better way to solve this problem?
Sorting all numbers in descending order is the simplest solution that occurs to us. But this doesn’t work.
For example, 548 is greater than 60, but in the output, 60 comes before 548. As a second example, 98 is greater than 9, but 9 comes before 98 in the output.
The solution is to use any comparison based sorting algorithm. Thus, instead of using the default comparison, write a comparison function myCompare() and use it to sort numbers.
Given two numbers X and Y, how should myCompare() decide which number to put first – we compare two numbers XY (Y appended at the end of X) and YX (X appended at the end of Y).
If XY is larger, then, in the output, X should come before Y, else Y should come before X.
For example, let X and Y be 542 and 60. To compare X and Y, we compare 54260 and 60542. Since 60542 is greater than 54260, we put Y first.
Calculating Permutations yield a higher time complexity.
A better solution in python would be:
def largestNumber(A):
maxlen = len(str(max(A)))
if all(v == 0 for v in A):
return '0'
return ''.join(sorted((str(v) for v in A), reverse=True,
key=lambda i: i*(maxlen * 2 // len(i))))
largestNumber([3, 30, 34, 5, 9])
The solution to this problem leads to an interesting transformation that is worth explaining.
Assume we want to know which of XY or YX is larger for given X and Y. Numerically, we want the largest of X.10^y + Y and Y.10^x + X, where the lowercase denote the number of digits of the uppercase variables.
Then with a little math, the comparison
X.10^y + Y < Y.10^x + X
can be rewritten
X / (10^x - 1) < Y / (10^y - 1)
so that XY < YX is certainly a transitive relation and defines a total order. This is very good news because it means that the problem can be reduced to ordinary sorting by using this modified comparison operation.
Now notice that X / (10^x - 1) is a periodic fractional number of the form 0.XXXX..., and to compare 0.XXXX... and 0.YYYY..., it suffices to compare over the longest period. Hence the comparison can work as an ordinary string comparison, except that when the end of the shorter string is reached, we cycle back to the first character.
E.g. 12345 > 12 because 12345 > 12|12|1 and 12105 < 12 because 12105 < 12|12|1.
The comparison function can be described as follows:
def Cmp(X, Y):
l= max(len(X), len(Y))
for i in range(l):
if X[i % len(X)] < Y[i % len(Y)]:
return 1 # X > Y
elif X[i % len(X)] > Y[i % len(Y)]:
return -1 # X < Y
return 0 # X == Y
I don't recommend this particular implementation, which will be slow because of the %.

Getting timeout error in this python while using itertools.permutation ? Please tell me how can i reduce time required by this program execution

Yet Another Minimax Problem
You are given non-negative integers. We define the score for some permutation () of length to be the maximum of for.
Find the permutation with the minimum possible score and print its score.
Note: is the exclusive-OR (XOR) operator.
code:
# Enter your code here. Read input from STDIN. Print output to STDOUT
import itertools
import math
from operator import xor
def per_me(g):
max =0
for r in range(0,len(g)-1):
if(xor(g[r],g[r+1])>max):
max=(xor(g[r],g[r+1]))
return max
n = int(raw_input())
arr = raw_input()
l = list(map(int,arr.split(' ')))
p = itertools.permutations(l)
count = 1000000000000
for i in p:
if(per_me(i)<count):
count = per_me(i)
print count
Input:
10
12 0 4 3 1 1 12 3 11 11
output:
8
How can I reduce time required by this code
Let i be the largest natural number such that some but not all of the input numbers have bit i set. The minimum score will be the minimum value of a xor b where a has bit i set, and b doesn't, and a and b are in the input list. It's easy to see that the score must be at least this large (since at some point in any permutation there must be a number with bit i set next to one without bit i set), and any permutation that groups all the inputs with bit i set first and the inputs without bit i set afterwards and puts the a and b from above together at the boundary achieves exactly that score (because a xor b has i as its highest bit, and all other adjacent numbers have highest bit less than i).
Even without thinking further, this reduces the problem to an O(n^2) problem, which should be good enough since n <= 3000.
def minxor(aa):
bits = unbits = 0
for a in aa:
bits |= a
unbits |= ~a
i = bits & unbits
while i & (i-1):
i &= i-1
xs = [a for a in aa if a & i]
ys = [a for a in aa if (a & i) == 0]
return min(x ^ y for x in xs for y in ys)
print minxor([1, 2, 3, 4])
print minxor([1, 2, 3])
print minxor([7, 6, 5, 4])
print minxor([12, 0, 4, 3, 1, 1, 12, 3, 11, 11])
(Note that in the code, i is not quite the same as in the description -- rather than the index of the largest bit that's present in some but not all of the inputs, it's the value of that bit).
One can optimize further by not comparing every x and y when computing the min. That reduces the solution to O(n log n), and one can find the solution even for quite large input lists:
def bestpair(xs, ys, i):
if i == 0:
return 0
x0 = [x for x in xs if (x&i)==0]
x1 = [x for x in xs if x&i]
y0 = [y for y in ys if (y&i)==0]
y1 = [y for y in ys if y&i]
choices = []
if x0 and y0:
choices.append(bestpair(x0, y0, i//2))
if x1 and y1:
choices.append(bestpair(x1, y1, i//2))
if choices:
return min(choices)
return bestpair(xs, ys, i//2) + i
def minxor(aa):
bits = unbits = 0
for a in aa:
bits |= a
unbits |= ~a
i = bits & unbits
while i & (i-1):
i &= i-1
return bestpair([a for a in aa if a & i], [a for a in aa if (a & i)==0], i)
print minxor(range(100000))

Python - Prime Number exercise

Note, this is not my homework assignment! I'm just trying to understand Python (and math, sadly) at the same time. I know the ultimate goal of this program is to get a list of prime numbers in the range 1 to 20, however, once it gets to the "for x in range..." line, I'm getting lost and the tutorial doesn't explain it in detail.
Could you please explain in plain English step by step and clarify specifically
a) what is x in the line for x in range (2,n)
b) in the line for x in range (2,n), what is n? Is it the same "n" at the bottom?
c) what is this n, x, n // x saying exactly. Please clarify the //
thanks if you can help
def isprime(n):
if n == 1:
print("1 is special")
return False
for x in range(2, n):
if n % x == 0:
print("{} equals {} x {}".format(n, x, n // x))
return False
else:
print(n, "is a prime number")
return True
for n in range(1, 20):
isprime(n)
a)
for x in range (2,n)
is the same like
for (x = 2; x < n; x++)
in some other language: a loop where x gets integer values between 2 and n-1 included.
b)
for x in range (2,n):
this n comes from the first def isprime(n) and is whatever this function is later called with. In this case it is always the same n from the bottom.
c)
print("{} equals {} x {}".format(n, x, n // x))
this writes the following text: A equals B x C where A is n, B is x and C is n/x rounded to the nearest smaller integer. It is so called integer division (e.g. 9 // 2 = 4)
a) Try this at the prompt:
help(range)
It will tell you that range(a,b) returns a list atarting as a, ending at b-1, so
range(2,10)
is
[2, 3, 4, 5, 6, 7, 8, 9]
Play at the prompt, type range(2,2), range(2,-1), range(2,3) and see what comes out. You'll see that n==1 isn't the only special case.
Now, something like for x in y iterates over the elements of y, which in your case would be a list. You can also verify this at the prompt:
for x in range(2,10) :
print x
b) the block starting with def isprime(n) is a function, with argument n. You can call it for any n: isprime(100). At the bottom of the code, you are iterating over range(1,20) (if in doubt type it into the prompt) and calling isprime for each value, i.e. 1,2,3,4,...,19.
Note that in this example, there isn't a need to create and return a list with range, you can use xrange, which is a generator. Type help(xrange) in the prompt...
a) x takes on the values from 2 to n-1 (since range excludes the upper bound)
b) No, it's the same n as in the method definition (i.e. the method argument)
c) Integer division

Categories

Resources