Automatically generate list from math function? - python

My idea is to run the 3n + 1 process (Collatz conjecture) on numbers ending in 1, 3, 7, and 9, within any arbitrary range, and to tell the code to send the lengths of each action to a list, so I can run functions on that list separately.
What I have so far is to specify unit digits 1,3,7 and 9 as: if n % 10 == 1; if n % 10 == 3 ...etc, and I think my plan needs some form of nested for loops; where I'm at with list appending is to have temp = [] and leng = [] and find a way for the code to automatically temp.clear() before each input to leng. I'm assuming there's different ways to do this, and I'm open to any ideas.
leng = []
temp = []
def col(n):
while n != 1:
print(n)
temp.append(n)
if n % 2 == 0:
n = n // 2
else:
n = n * 3 + 1
temp.append(n)
print(n)

It's unclear what specifically you're asking about and want to know, so this is only a guess. Since you only want to know the lengths of the sequences, there's no need to actually save the numbers in each one—which means there's only one list created.
def collatz(n):
""" Return length of Collatz sequence beginning with positive integer "n".
"""
count = 0
while n != 1:
n = n // 2 if n % 2 == 0 else n*3 + 1
count += 1
return count
def process_range(start, stop):
""" Return list of results of calling the collatz function to the all the
numbers in the closed interval [start...stop] that end with a digit
in the set {1, 3, 7, or 9}.
"""
return [collatz(n) for n in range(start, stop+1) if n % 10 in {1, 3, 7, 9}]
print(process_range(1, 42))
Output:
[0, 7, 16, 19, 14, 9, 12, 20, 7, 15, 111, 18, 106, 26, 21, 34, 109]

Related

Find large number in a list, where all previous numbers are also in the list

I am trying to implement a Yellowstone Integer calculation which suggests that "Every number appears exactly once: this is a permutation of the positive numbers". The formula I have implemented to derive the values is as follows:
import math
yellowstone_list = []
item_list = []
i = 0
while i <= 1000:
if i <= 3:
yellowstone_list.append(i)
else:
j = 1
inList = 1
while inList == 1:
minus_1 = math.gcd(j, yellowstone_list[i-1])
minus_2 = math.gcd(j, yellowstone_list[i-2])
if minus_1 == 1 and minus_2 > 1:
if j in yellowstone_list:
inList = 1
else:
inList = 0
j += 1
yellowstone_list.append(j - 1)
item_list.append(i)
i += 1
The issue becomes that as i increases, the time taken for the formula to determine the value of j also increases (naturally as i is increasingly further away from the start point of j).
What I would like to do is determine the largest value of j in the yellowstone_list, where all the values of 1 to j are already in the list.
As an example, in the below list, j would be 9, as all the values 0 - 9 are in the list:
yellowstone_list = [0, 1, 2, 3, 4, 9, 8, 15, 14, 5, 6, 25, 12, 35, 16, 7]
Any suggestions on how to implement this in an efficient manner?
For the "standalone" problem as stated the algorithm would be:
Sort the list.
Run a counter from 0 while in parallel traversing the list. Once the counter value is unequal to the list element, then you have found one-past the wanted element.
Something like the following:
x=[0, 1, 2, 3, 4, 9, 8, 15, 14, 5, 6, 25, 12, 35, 16, 7]
y=sorted(x)
for i in range(1, len(y)):
if y[i]!=i:
print(i-1)
break
But in your case it appears that the initial list is being built gradually. So each time a number is added to the list, it can be inserted in a sorted manner and can be checked against the previous element and the traversal can start from there for more efficient process.
This is how I would do it:
lst.sort()
for c, i in enumerate(lst):
if c + 1 < len(lst) and lst[c + 1] != i + 1:
j = i
break
else:
j = i
Basically, the list is sorted, and then, it loops through each value, checking if the next value is only 1 greater than the current.
After some time to sit down and think about it, and using the suggestions to sort the list, I came up with two solutions:
Sorting
I implemented #eugebe Sh.'s solution within the while i < 1000 loop as follows:
while i <= 1000:
m = sorted(yellowstone_list)
for n in range(1, len(m)):
if m[n]!=n:
break
if i == 0:
....
In List
I ran an increment to check if the value was in the list using the "in" function, also within the while i < 1000 loop, as follows:
while i <= 1000:
while k in yellowstone_list:
k += 1
if i == 0:
....
Running both codes 100 times, I got the following:
Sorting: Total: 1:56.403527 seconds, Average: 1.164035 seconds.
In List: Total: 1:14.225230 seconds, Average: 0.742252 seconds.

Project Euler #23 - Non Abundant Sums

This is the task:
Problem 23
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis >even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
This is my code:
import time
import math
start = time.time()
abundant_num_list = []
def checkAbundant():
for n in range(1, 28123):
factor_sum = 0
other_pair_factor = 0
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
if math.floor(math.sqrt(n)) == math.sqrt(n):
other_pair_factor = 0
else:
other_pair_factor = n // i
factor_sum += (i + other_pair_factor + 1)
if n < factor_sum :
abundant_num_list.append(n)
def NonAbundantSums():
abundant_sum_list = []
all_num_list = []
non_abun_list = []
non_abun_sum = 0
for i in range(len(abundant_num_list)):
for j in range(i, len(abundant_num_list)):
if abundant_num_list[i] + abundant_num_list[j] <= 28123:
abundant_sum_list.append(abundant_num_list[i] + abundant_num_list[j])
for i in range(1, 28124):
all_num_list.append(i)
non_abun_list = [int(a) for a in (set(all_num_list) - set(abundant_sum_list))]
for i in range(len(non_abun_list)):
non_abun_sum += non_abun_list[i]
print(non_abun_sum)
checkAbundant()
NonAbundantSums()
end = time.time() - start
print("Done in", end, "seconds")
If it looks inefficient, i know, I'm new to coding. Python is my first programming language. I noticed a weird problem for my non_abun_list, where when retrieving the difference for set(all_num_list) and set(abundant_sum_list), the first and second index of abundant_sum_list is 2 and 30, so in my mind, non_abun_list shoud look like
[1, 2, 3, 4... ,22, 23, 25, 26, 27, 28, 29, 31, 32]
instead i got this
[1, 2, 3, 4... ,22, 23, 8209 ,25, 26, 27, 28, 29, 8219, 31, 32]
and i don't know how I got this list instead.
Can someone explain to me what's wrong with my code?
My result is 4352518 in ~25 seconds
Answer is 4179871
This is not an answer
(OP cannot participate in chat due to rep requirement)
You should consider your coding style. If you write concise functions to perform a task and have those functions return a value(s) then you can easily test those functions to see if they work. This makes it easier to determine what IS working.
For example when checking for abundancy you have to do two things: find the divisors of a number and compare their sum to that number.
def divisors(n):
'''return divisors of n'''
d = [1]
for i in range(2, int(pow(n,.5))+1):
if (n % i) == 0:
other = n // i
if other == i:
pair = [i]
else:
pair = [i,other]
d.extend(pair)
return d
def check(n):
'''return True if abundant'''
return sum(divisors(n)) > n
Now you can easily test both functions against known inputs and outputs if you start having problems. Once you know they work you don't have to consider them as a source of errors.
usage:
abundant_numbers = []
for n in range(12,28124):
if check(n):
abundant_numbers.append(n)
Test a couple of numbers:
>>> divisors(16)
[1, 2, 8, 4]
>>> divisors(1056)
[1, 2, 528, 3, 352, 4, 264, 6, 176, 8, 132, 11, 96, 12, 88, 16, 66, 22, 48, 24, 44, 32, 33]
>>> check(16)
False
>>> check(1056)
True
>>>
Yep, that looks right :).
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
if math.floor(math.sqrt(n)) == math.sqrt(n) == i:
other_pair_factor = 0
else:
other_pair_factor = n // i
factor_sum += (i + other_pair_factor)
factor_sum += 1
For this specific part of checkAbundant(), i should include "== i " at line 3 because I only want the factor that will repeat twice to only count once for square numbers
For example, the pair factor as I would like to call for 36 is 1 x 36, 2 x 18, 3, 12, 4 x 9, 6 x 6.
For efficiency, I only find the first half of the factor pair, the other half is obtained through n // i. So in order to have the sum of proper factors of a number, I can't have repeated factors.
Without adding " ==i " I have made it so that for any square abundant numbers, their other half of the factor is not accounted for when summing the total factors up.
Another mistake i fixed in checkAbundant() is in line 8, where factor_sum += (i + other_pair_factor + 1)
This resulted in for every loop, factor_sum would have an additional 1, which will ruin the result. To fix that, i added 1 after the for loop
Overall, I would say it was a pretty rookie mistake. >.<

light gremlins - finding all the multiplication numbers of a prime in a range

I was trying to answer a question called "lightgremlins" on IEEEXTREME.
given a array number of gremlins and the prime numbers each chose return the numbers in range that are still on after all gremlins toggled there prime multiplied numbers.
given the input:
30 3 2 3 5
output:
15
case consists of a hallway of length 30, and three gremlins. The action of the gremlins is as
follows:
The first gremlin flips switches {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}. All of these
switches were previously off, so they are now on.
The second gremlin flips switches {3, 6, 9, 12, 15, 18, 21, 24, 27, 30}. Of these, {6, 12, 18, 24, 30}
were previously on, so they are now off. This results in the following switches being on: {2, 3, 4, 8, 9,
10, 14, 15, 16, 20, 21, 22, 26, 27, 28}.
The third gremlin flips switches {5, 10, 15, 20, 25, 30}. Of these, {10, 15, 20} were previously on, so
they are now off. This results in the following switches being on: {2, 3, 4, 5, 8, 9, 14, 16, 21, 22, 25,
26, 27, 28, 30}.
Thus, there are 15 switches on at the end of the night.
Now my code is very straight forward:
testcases=int(input())
for i in range(0,testcases):
array = input().split(' ')
arrayofnumbers = [int(x) for x in array]
#print(arrayofnumbers)
onCount=0
for j in range(1,arrayofnumbers[0]+1):
primeCount=0
for p in arrayofnumbers[2:len(arrayofnumbers)]:
if j%p == 0:
primeCount += 1
if primeCount % 2 == 1:
onCount += 1
print(onCount)
now this seems to work ok for small arrays or i think. i'm failing half of the test cases and i don't really understand why. perhaps this doesn't hold for very large arrays? perhaps my entire approach is wrong?
i have changed my code to use LCM and count amount of iterations but still this didn't solve the rest of the test cases pretty much stayed the same. this is my code:
from math import gcd
testcases=int(input())
for i in range(0,testcases):
array = input().split(' ')
arrayofnumbers = [int(x) for x in array]
#print(arrayofnumbers)
lcm = 1
for i in arrayofnumbers[2:]:
lcm = int(lcm * i / gcd(lcm, i))
#print(lcm)
if lcm >= arrayofnumbers[0]:
onCount=0
for j in range(1,arrayofnumbers[0]+1):
primeCount=0
for p in arrayofnumbers[2:len(arrayofnumbers)]:
if j%p == 0:
primeCount += 1
if primeCount % 2 == 1:
onCount += 1
print(onCount)
if lcm < arrayofnumbers[0]:
numiters=int(arrayofnumbers[0]/lcm)
onCount = 0
extraonCount=0
for j in range(1, lcm+1):
primeCount = 0
for p in arrayofnumbers[2:len(arrayofnumbers)]:
if j % p == 0:
primeCount += 1
if primeCount % 2 == 1:
onCount += 1
onCount = onCount * numiters
for j in range(1, (arrayofnumbers[0]-(lcm*numiters))+1):
primeCount = 0
for p in arrayofnumbers[2:len(arrayofnumbers)]:
if j % p == 0:
primeCount += 1
if primeCount % 2 == 1:
extraonCount += 1
onCount += extraonCount
print(onCount)
using a different approach using sets of divisible numbers i'm not getting any test case timeouts but wrong answers and a bit more correct test cases but still not a full right answer.
using this idea:
click link
testcases=int(input())
for i in range(0,testcases):
array = input().split(' ')
arrayofnumbers = [int(x) for x in array]
arrayOfon = []
arrayIterate = []
arrayPrimes = []
for j in arrayofnumbers[2:]:
arrayPrimes.append(j)
arrayPrimes.sort()
print(arrayPrimes)
for j in arrayPrimes:
num=0
num = int(arrayofnumbers[0] // j)
arrayOfon.append(num)
print(arrayOfon)
for j in arrayPrimes[1:]:
arrayIterate.append(j)
print(arrayIterate)
for j in range(0, len(arrayIterate)):
x = 0
y = 0
y = arrayOfon[0]
x = y // arrayIterate[j]
arrayOfon[0] = (y - x) + (arrayOfon[j+1] - x)
print(arrayOfon[0])
Let lcm be the least common multiple, the counts will repeat every lcm numbers, so you don't need to loop over the whole range, just count how many switches are on in the range 1..lcm, then multiply that by int(n/lcm) (i.e. how many times the sequence will repeat as whole) and add the counts for the last items, i.e. from lcm*int*n/lcm) to end.
Simple example:
if the number of switches is 33, and there are two gremlins: 2 and 3, lcm(2,3)=6 so you don't need to count all the way from 1 to 33, because the counts will repeat every 6 switches, and will repeat int(33/6)=5 times. So you only have to count the switches from 1 to 6, and multiply that count by 5, and add the count for the range 31...33

Find integer with most divisor from list of integers

I am trying to write a function to find integer with most divisor from a list, but i am getting the wrong output. This is how my function looks.
def find_my_integer_divisor(mylist):
def find_divisor(k):
count =0
for i in range (1,k+1):
if k%i==0:
count +=1
return count
A=mylist[0]
for x in mylist [0:]:
A=find_divisor(x)
return A
It returns the count of the last entry in mylist. I know I have to compare the value counts from each entry and returns the integer with the most count but don't know how to do it.
This should work:
def find_divisor(k):
count =0
for i in range (1,k+1):
if k%i==0:
count +=1
return count
def find_my_integer_divisor(mylist):
return max(mylist, key=find_divisor)
Instead of actually finding all the proper factors, we can much more efficiently calculate the number possible by doing a prime factorization.
For example,
288 == 2**5 * 3**2
and the number of proper factors is
(5 + 1) * (2 + 1) - 1
^ ^ ^
number number omit one case:
of twos of threes 5 2s and 2 3s == 288,
used in used in which is not a proper
factor, factor factor of itself
0..5
(six possible
values)
To do a prime factorization, we need to start by generating primes:
def primes(known_primes=[7, 11, 13, 17, 19, 23, 29]):
"""
Generate every prime number in ascending order
"""
# 2, 3, 5 wheel
yield from (2, 3, 5)
yield from known_primes
# The first time the generator runs, known_primes
# contains all primes such that 5 < p < 2 * 3 * 5
# After each wheel cycle the list of known primes
# will be added to.
# We need to figure out where to continue from,
# which is the next multiple of 30 higher than
# the last known_prime:
base = 30 * (known_primes[-1] // 30 + 1)
new_primes = []
while True:
# offs is chosen so 30*i + offs cannot be a multiple of 2, 3, or 5
for offs in (1, 7, 11, 13, 17, 19, 23, 29):
k = base + offs # next prime candidate
for p in known_primes:
if not k % p:
# found a factor - not prime
break
elif p*p > k:
# no smaller prime factors - found a new prime
new_primes.append(k)
break
if new_primes:
yield from new_primes
known_primes.extend(new_primes)
new_primes = []
base += 30
which can be tested like
from itertools import islice
print(list(islice(primes(), 500)))
giving
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, ...
Now that we have primes, we can count the occurrences of each prime factor like so:
def prime_factor_count(n):
"""
Factorize n and yield (factor, count) for each distinct factor
"""
if n < 2:
return
else:
for p in primes():
count = 0
while not n % p:
count += 1
n //= p
if count:
yield (p, count)
if n == 1:
# number is fully factored
break
elif p*p > n:
# no smaller prime factors - remainder is prime
yield (n, 1)
break
which we can test like
print(list(prime_factor_count(288))) # => [(2, 5), (3, 2)]
which you should recognize from above, 288 == 2**5 * 3**2. Now we can
def num_proper_factors(n):
total_factors = 1
for factor, count in prime_factor_count(n):
total_factors *= (count + 1)
return total_factors - 1
which tests like
print(num_proper_factors(288)) # => 17
and finally,
def num_with_most_divisors(lst):
return max(lst, key=num_proper_factors)
QED.
short answer: use max with a key function like your's find_divisor as show by #rofls.
Long answer: in each iteration you need to compare yours previous value with the current value in your list, if the current value have a bigger count of divisor change A otherwise don't, the problem in your code is that you don't do this check. You can do something like this
def max_divisor_count(my_list):
result = my_list[0]
for n in my_list[1:]: # start in 1 because 0 is already in result
if find_divisor(n) > find_divisor(result):
result = n
return result
and this is more or less the same that the max with key-function solution does.
Of course this can be improved a little more to avoid repeat calculations like this
def max_divisor_count(my_list):
result = my_list[0]
div_count = find_divisor(result)
for n in my_list[1:]: # start in position 1 because 0 is already in result
if result != n:
temp = find_divisor(n)
if temp > div_count:
result = n
div_count = temp
return result
This is a generator expression alternative. Note I use itertools.tee to create 2 instances of the generator. The first is to calculate the max, the second to feed enumerate.
The below example also demonstrates how you can use a list comprehension to return all integers with the maximum number of divisors.
from itertools import tee
lst = [1, 2, 3, 6, 8, 10, 14]
gen1, gen2 = tee(sum(k%i==0 for i in range(1, k+1)) for k in lst)
divmax = max(gen1)
[lst[i] for i, j in enumerate(gen2) if j == divmax]
# [6, 8, 10, 14]

I want to know how to add to digits together in a list. Say the number is 10. I need it to add 1 + 0 to the new list

I want to know how to add to digits together in a list. Say the number is 10. I need it to add 1 + 0 to the new list. If the item in the list is 11 it needs to add 2 to the list
def main():
#Define List
mylist = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
print(mylist)
newlist = []
for each in mylist:
if (each % 2 == 0):
newlist.append(each)
else:
newlist.append(each + each)
for each in newlist:
if each >= 10:
newlist.append(each + each)
print(newlist)
main()
To get the digit sum of a number, you should convert the number to a string, loop over the string, and add all chars together (after converting them to int again):
def get_digit_sum(num):
return sum(int(x) for x in str(num))
To do this for a list of numbers, you should use list comprehension:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [get_digit_sum(x) for x in my_nums]
>>print(digit_sums)
[2, 4, 11, 12]
This is also possible to do in one expression:
>>my_nums = [11, 22, 56, 345]
>>digit_sums = [sum(int(x) for x in str(num)) for num in my_nums]
As per abarnet's comment, you may want the number 345 to be converted to 3+4+5=12, and the convert 12 to 1+2=3. This can be done using recursion. By using a max_digits parameter, you can specify the maximum number of digits in the returned number.
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
if len(str(d)) > max_digits:
return get_digit_sum(d)
return d
or a bit shorter:
def get_digit_sum(num, max_digits=1):
d = sum(int(x) for x in str(num))
return get_digit_sum(d) if len(str(d)) > max_digits else d
Both of the above functions would then yield:
>>my_nums = [11, 22, 56, 345]
>>print [get_digit_sum(x) for x in my_nums]
[2, 4, 2, 3]
It looks like your code is trying to do a little bit more than what you describe - in particular, you double any odd numbers. Because you're doing two things to each number (possibly double, sum the digits), you don't want to put it in the list until both steps are done. Instead do something like this:
for each in mylist:
if each % 2 != 0:
each *= 2
if each >= 10:
each = # sum of digits
newlist.append(each)
There's a couple of ways you could sum the digits. You can use divmod to get the quotient and the remainder of the number divided by 10 - the remainder is the units column, the quotient is every column to the left of that:
if each >= 10:
q, r = divmod(each, 10)
each = q + r
the other way is to get the string representation, which lets you iterate over every digit, convert it back to a number and add them:
if each >= 10:
each = sum(int(d) for d in str(each))
this is possibly easier to understand It is, however, a fair bit slower - which might matter if you have a very large amount of input.
These two approaches do work differently if you end up with any three or more digit numbers in the list - for 110, the divmod version will do 11 + 0 = 11, while the string version will do 1 + 1 + 0 = 2.
Also note that neither is guaranteed to end up with a single-digit number in the end - for 99, both of these will give you 18. If you want that further reduced to 9, you can change the if to a loop:
while each >= 10:
each = sum(int(d) for d in str(each))
to do this for the divmod version, you could put it into a recursive function instead:
def digit_sum(number):
q, r = divmod(number, 10)
if q > 10:
q = digit_sum(q)
return q+r
Making the same change to the divmod version as the string version appears to give the same answer in every case I've tried, but I have no idea if this is guaranteed to be the case.
> [int(d) for d in str(123)]
[1, 2, 3]
Try this:
A function that sums the digits for a given number:
def sum_of_digits(num):
return sum([int(x) for x in str(num)])
And a list comprehension to apply it to the entire list:
newlist=[sum_of_digits(number) for number in mylist]
I believe I know what you are going for. If the value is even and less than 10 add it to the new list, if the value is odd then double it and if that is less than 10 add it to the new list. Now if the value is greater than 10 then take the sum of all the digits and add it to the list.
I am sure there is a better way to do this, but this is what I came up with.
list = [4,5,5,2,7,2,0,4,1,2,3,4,5,6,7,8]
newlist = []
for i in list:
if i % 2 == 0 and len(str(i)) > 1:
newlist.append(sum([int(x) for x in str(i)]))
elif i % 2 == 0:
newlist.append(i)
elif len(str(i*2)) > 1:
newlist.append(sum([int(x) for x in str(i*2)]))
else:
newlist.append(i*2)
print newlist
input: [4, 5, 5, 2, 7, 2, 0, 4, 1, 2, 3, 4, 5, 6, 7, 8]
outcome: [4, 1, 1, 2, 5, 2, 0, 4, 2, 2, 6, 4, 1, 6, 5, 8]

Categories