I am trying to find the LCM of first 20 natural numbers (Project Euler question 5). For that, my algorithm is:
have numbers 1 to 20 in a list
Divide only those elements of the list that are divisible by i where i is in the range (2-20).
Whatever numbers are left in the list, multiply them and that will be the lcm.
This is the naivest algorithm which we actually used to calculate lcm in school for the first time.
Now, I donot know how to divide the elements of the list based on the condition.
I have tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for x in a:
if(x%2==0):
x=x/2
This does not seem to work.
I also tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[if(x%2==0): x/2 for x in a]
the above with both with and without ":" after the if condition. This does not work. I have the following questions:
a. Why isn't the first loop working correctly?
b. Can someone tell me how I can do this?
c. Will my algorithm work correctly?
a. Why isn't the first loop working correctly?
For the same reason as:
Foreach in Python not working as expected
b. Can someone tell me how I can do this?
You can do either:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i, x in enumerate(a):
if x%2==0:
a[i]=x/2
Or:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[x/2 if x%2==0 else x for x in a]
c. Will my algorithm work correctly?
I don't think so. You'll end up dividing everyone by itself and the result will always be 1.
But there are other questions here in SO that have simple answers, like:
find least common multiple of numbers 1-20
a) Why is this loop not working correctly?
As #jose-ricardo-bustos-m indicates, the x is not a reference, is a local copy to each element of the array a, and cannot modify the array in the for loop. You can use, instead:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i,x in enumerate(a): #used to provide a value, and an index
if(x%2==0):
a[i]=x/2
b) Can someone tell me how I can do this?
You can try to use the ternary if operator and list comprehension:
a = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
b = [x/2 if x%2==0 else x for x in a]
c) Will my algorithm work correctly
You have to keep track of the numbers you have already used, and you might need to divide by the same number more than once. But if you do that, and keep dividing by the same number _until the resulting list is equal to the previous one, and then move to the next, you can later multiply all numbers used, times the remainder of the list (but if you go to the max number in the list, the remaining list will contain just 1's).
def f(l,n): # divides items in a which are divisible by n, or leaves them
return [x/n if x%n==0 else x for x in l]
lcm = 1
a=[2,3,4,5,6,7]
# we go from the smallest to the largest number in your list
for i in range(2,max(a)+1):
repeat_next_time = True
while repeat_next_time:
b = f(a,i)
if a != b:
print('Using %s as a factor' % i)
a = b
lcm *= i
# print(a) # to get the status of the a list
else:
repeat_next_time = False
# finally, for numbers which might have not been divided yet,
# multiply the lcm by all of the remaining items
lcm *= reduce(lambda x,y: x*y, a)
It works even if there are common divisors, or repeated numbers in the list. Try, for instance, with a = [2,2,2], or a = [2,3,6], or a = [8,7,4,7].
a) the variable x takes the value of the list a , but not modified, it is not a reference of list, the following code does what you want:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i in range(len(a)):
if(a[i]%2==0):
a[i]=a[i]/2
b) y C)
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
def f(x):
if(x%2==0):
return x/2
return x
a1=[f(x) for x in a]
Whatever numbers are left in the list, multiply them and that will be the lcm.
reduce(lambda x, y: x*y, a1)
Related
#create a simple list in python
#list comprehension
x = [i for i in range(100)]
print (x)
#using loops
squares = []
for x in range(10):
squares.append(x**2)
print (squares)
multiples = k*[z for z in x] for k in squares
So in the last line of code I am trying to multiply both the lists. the problem is the lists are not of the same side and k*[z for z in x] this part is also incorrect.
For problems with iteration, I suggest anyone to check Loop Like A Native by Ned Batchelder and Looping like a Pro by David Baumgold
Option 1
If you want to multiply them as far as the shortest list goes, zip is your friend:
multiples = [a * b for a, b in zip (x, squares)]
Option 2
If you want a matrix with the product, then you can do it like this
result = [
[a * b for a in x]
for b in squares
]
I don't quite understand what the desired output would be. As the function stands now, you would have a list of lists, where the first element has 100 elements, the second one 400, the third 900, and so on.
One thing that's strange: The expression [z for z in x] defines a list that is identical to x. So, you might just write k*x
If you want to multiply the elements of both lists, you would have to write [[k*z for z in x] for k in squares]. This would lead to a list of 10 lists of 100 elements (or a 10x100-matrix) containing the products of your lists.
If you want to have one list of length 100 in the end that holds some kind of products, you will have to think about how to proceed with the shorter list.
EDIT: Or if you want to multiply them as far as possible until you reach the end of the shorter list, FRANCOIS CYRIL's solution is an elegant way to do so.
You can loop on each array to multiply element by element at the same position in a result array:
i = 0
arrayRes = []
while i < min (len(array1),len(array2)):
arrayRes.append(array1[i]*array2[i])
i+=1
Or do you prefer to multiply them, matrix way?
x = 0
y = 0
arrayRes = []
while x < len(array1):
arrayRes.append([])
while y < len(array2):
arrayRes[x].append(array1[x]*array2[y])
y+=1
x+=1
While variants of this question have been asked numerous times on this site, I haven't found any information on how to do 'ordered combinations' with a given list.
First of all, I don't exactly know what the correct term for this function is, but I will use this list:
list = [1,2,3,4,5,6,7,8,9,10]
What I want to find is how many possible ways this list can be ordered, so that
list[0] < list[1] < list[2] ... < list[len(list)-1] (Ascending order w/o repeats )
But
list[0] + 1 doesn't have to be equal to list[1] (Doesn't matter which numbers are chosen, so long that they are in ascending order and are in the list)
And, assuming outList is a qualifying list sourced from list
len(outList) doesn't have to be to len(list) - 'Qualifying' lists do not have to be the same length of the given list, but it must not be longer.
Some examples of what would fit under these rules:
[1,4,5,9]
[2,6,7,8,9]
[1,2,4,8]
[8,10]
Some non-examples:
[1,3,2,5,10]
[1,1,10]
[5,2,8,7,9]
Numbers CANNOT repeat, and they must strictly be larger than the previous number.
How would I go about making such a function? I haven't a clue at how to approach such a problem. I tried using a for loop, but I couldn't seem to get that to work properly.
Edit: sorry this question was unclear, and if it still is, because I really don't know what term I would use. I didn't know how to phrase it correctly, so I added some more detail, and my version of the answer is down below. Clearly it is not optimized. Btw AlexanderCĂ©cile, if you look at my history, I used to do js and jQuery (not that I don't anymore, but I changed my focus), so the function follows the naming standards of js.
Second edit: All these answers are quite different from each other, which shows the beauty of coding :) - My solution is quite basic, although it does work. Do these work quicker on higher length lists, such as [1,2,3,4...100,101]?
As I understand your question, you want to know how many different lists there are with some subset of the elements as lst, kept in order. Since each subset can only exist in one order, the answer is simply the number of subsets: 2^n where n is the length of the list.
def count_subsets(lst):
return 2 ** len(lst)
For example, if the list is [1, 2, 3] then there are 2^3 = 8 ordered sublists:
[]
[1]
[2]
[3]
[1, 2]
[1, 3]
[2, 3]
[1, 2, 3]
If you want to exclude the empty list and/or the original list, you can simply do 2 ** len(lst) - 1 or max(0, 2 ** len(lst) - 2), as appropriate. The max(0, ...) handles the special case when your input list is empty.
The above handles the case like your example when the elements of the input list are all distinct. If there may be repeated elements, then the formula above overcounts. To fix it, we can use a Counter to find the number of copies of each element. If there are k copies of some element, then instead of 2 ** k combinations, we should count k + 1 sublists containing 0, 1, 2, ..., k copies.
from collections import Counter
def count_subsets(lst):
r = 1
for k in Counter(lst).values():
r *= k + 1
return r
You can do this mathematically using the formula to calculate the number of combinations.
import math
def binomial_coeff(n, k):
return math.factorial(n) // (math.factorial(k) * math.factorial(n - k))
def num_all_combinations(lst_len):
return sum(binomial_coeff(lst_len, i) for i in range(lst_len))
list1 = list(range(10))
print(num_all_combinations(len(list1))) # prints 1023
The binomial_coeff function uses the combinations formula (also known as the binomial coefficient) to get the number of combinations for a list of size n with groups of size k. We then use the num_all_combinations function to get the number of combinations for all group sizes and add them together.
You can even simplify this further using the sums of binomial coefficients identity as suggested by #kaya3. This would result in the following code:
list1 = list(range(10))
print(2**len(list1) - 1) # prints 1023
This solution is most likely unoptimized, but I somehow figured out what I wanted to do. Is there a nice way to improve this?
def orderedCombinations():
z = 0
for x in range(len(list1)):
comb = combinations(list1, x)
for i in list(comb):
z += 1
print(str(z))
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)]
Multiple number inputs
below is just how I chose to start writing my code
def main():
numbers = input()
if numbers == "0":
exit()
else:
number_list = [int(i) for i in numbers.split()]
def calculate_gcd(number_list):
for i in range(1,smallest_number(number_list)+1):
for n in range(0,len(number_list)):
if number_list[n] % i == 0:
check_list += number_list[n]
more code - but not important for the question im asking
my code was hardly complete and only worked for max 3 size lists, sadly.
How I thought of logic
Read input -> split by space, put it in list
sort the list
make a variable (divisor), and set it to 1
while divisor <= sortedlist[0] (which is smallest in list)
5. if every element % divisor == 0, then gcd = divisor, then divisor+=1
loop until it is no longer true
Problem I found
It requires stupid effort, it will actually not run and give runtime error.
I'm having trouble finding a way to check No.5 (in bold)
I know that there is gcd function, but it only deals with two inputs.
and it comes down to same question, how do I make sure 'all' elements divides down to zero?
Any suggestion of making gcd logic and comment on No.5 (bold) ?
Thank you
Instead of tackling the bigger problem, why not tackle a smaller problem. How do you find the gcd of two numbers? Well, there are multiple algorithms for this. Let us use the iterative one:
def gcd_iterative(a, b):
while b:
a, b = b, a % b
return a
Now, one thing to realize is that, if you have multiple numbers, and you want to find the gcd of all numbers, then it is simply:
gcd(gcd(...(a, b), c), ...)
In simpler terms, if you want to find the gcd of three numbers (a, b, c), then you would do the following:
gcd = gcd_iterative(a, b)
gcd = gcd_iterative(gcd, c)
So, now if you have a list of numbers, lst, you can do the following:
>>> gcd = lst[0]
>>> for num in lst[1:]:
gcd = gcd_iterative(gcd, num)
>>> print(gcd)
I have an array A = [1 - 100] and I need to find the sum of all the two digit values in this array. How would I approach this? I have tried :
def solution(A):
A =array[0-100])
while A > 9 & A < 99
total = sum(A)
print "%s" % total
)
Is there a function that given an array consisting of N integers returns the sum of all two digit numbers i.e A = [1,1000,80, -91] the function should return -11(as the two are 80 and -91). not a range, multiple array
You can use a list comprehension and check if the length of the string-format is equal to 2, like so:
sum([x if len(str(x))==2 else 0 for x in xrange(1,101)])
Use the keyword and rather than the bitwise &.
Edit: a fuller answer, as that's not the only thing wrong:
def solution():
A = range(101)
total = sum([a for a in A if 9 < a <= 99])
print total
This uses list comprehension and chained inequalities, so is pretty 'pythonic'.
There is tons of errors in your code, please next time before posting,spend some time try to figure it out yourself and be sure that your code at lest doesn't contain any obvious syntax error.
By array, I assume you're talking about a list. And change it to range(101) for every number from 0 to 100
def solution(A):
return sum([x for x in range(A) if len(str(abs(x))) == 2])
print(solution(101))
As a side note, use and instead of & since that's a bitwise-or sign.
Here are a couple of ways to go about the problem, the first is most similar to the approach you appear to be trying:
def solution1(array):
total = 0
for a in array:
if 9 < a < 100:
total += a
return total
print(solution1(range(101)))
And here's a more compact solution using a comprehension (actually, a generator expression):
def solution2(array):
return sum(a for a in array if 9 < a < 100)
print(solution2(range(101)))
Note that in your original you're confusing loops and conditionals.