def tribonacci(signature, n):
f = 0
if n == 0:
return []
if n == 1:
return [signature[0]]
if n == 2:
return [signature[0], signature[1]]
while len(signature) != n:
i = signature[0 + f] + signature[1 + f] + signature[2 + f]
signature.append(i)
f += 1
return signature
That's a Tribonacci(same with Fibonacci but with 3 numbers) code from codewars.com , I know that it could be more beautiful and elegant but i want to know how to reduce this particular part:
if n == 0:
return []
if n == 1:
return [signature[0]]
if n == 2:
return [signature[0], signature[1]]
Thanks!
You can see in your if statements, when n==0 return is empty list, for n==1, return one item in a list and also for n==2 return two items in a list.
So for that you can do in a one if statement as below:
if 0 <= n < 3:
return list(signature[:n])
And here is your full code for your problem.
def tribonacci(signature, n):
#your code here
f = 0
if 0 <= n < 3:
return list(signature[:n])
while len(signature) != n:
i = signature[0 + f] + signature[1 + f] + signature[2 + f]
signature.append(i)
f += 1
return signature
The 3 cases 0, 1, 2 can be reduced to one, because all return the signature list until the given n
if n < 3: # if 0 <= n < 3: can be used for satefy
return signature[:n]
Related
I am trying to perform a Collatz algorithm on the following code. It works fine when I use a range of 1-10 etc... However, if the range is for example 1-500,000 it's too slow and won't ever show me the output of the longest sequence.
numberArray = []
s=int(1)
f=int(10)
def collatz(n):
global count
if n == 1:
count += 1
numberArray.append(count)
return True
elif (n % 2) == 0:
count += 1
collatz(n/2)
else:
count += 1
collatz(3*n+1)
for i in range (s, f+1):
count = 0
ourNumber = i
collatz(i)
print(max(numberArray))
Stef means something like this, which uses a dictionary to memorise the values that have already been counted:
s = 1
f = 10000000
def collatz(n):
if n in collatz.memory:
return collatz.memory[n]
if (n % 2) == 0:
count = collatz(n//2)+1
else:
count = collatz((3*n+1)//2)+2
collatz.memory[n] = count
return count
collatz.memory = {1:0}
highest = max(collatz(i) for i in range(s, f+1))
highest_n = max(collatz.memory, key=collatz.memory.get)
print(f"collatz({highest_n}) is {highest}")
Output:
collatz(8400511) is 685
Use lru_cache decorator. Its function to memorize (cache) the returned value of function called with specific argument.
Also read how to write clean code in python
The next code solves your problem
from functools import lru_cache
number_array = []
s = 1
f = 500000
#lru_cache
def collatz(n: int):
if n == 1:
return 1
elif n % 2 == 0:
return 1 + collatz(n // 2)
else:
return 1 + collatz(3 * n + 1)
for i in range(s, f + 1):
number_array.append(collatz(i))
print(number_array)
I want to find a peak in a list.
I want to find if a number is bigger than his neighbors.
if it is the first object in the list I want to check only if he is bigger than the one after him.
if it is the last object in the list I want to check the one before him.
def peaks(lst):
num = 0
leni = len(lst)
print(leni)
for i in range(1,leni - 1):
if lst[i] > lst[i-1] and lst[i] > lst[i+1]:
num = num + 1
for i in range(leni):
print(i)
if i == 0:
if lst[i] > lst[i+1]:
num = num + 1
elif i == leni+1:
if lst[i] > lst[i-1]:
num = num + 1
return num
This code doesn't work when it should check the last object.
When I try [1,2,3] I get 0 instead of 1.
You could do some trickery to count peaks by making the boundary special cases not so special any more:
def peaks(lst):
lst = [float("-inf")] + lst + [float("-inf")]
return sum(a < b > c for a, b, c in zip(lst, lst[1:], lst[2:]))
Hello and welcome to Stackoverflow!
Note that range(leni) is a sequence of numbers from 0 to leni - 1 inclusive. So your condition i == leni+1 is never satisfied. You may replace it to i == leni - 1.
Note also that you don't need a second loop. You may just replace it with
if lst[0] > lst[1]:
num = num + 1
if lst[-1] > lst[-2]:
num= num + 1
Here lst[-1] is the same as lst[leni - 1] and lst[-2] is the same as lst[leni - 2].
Alternative way.
Check the extremes then check the core, three by three:
def count_peaks(ls):
res = [ls[0] > ls[1], ls[-1] > ls[-2]]
for n in range(len(ls)-2):
a, b, c = ls[n:n+3]
res.insert(-1, b > max([a, c]))
return res
Insert before the last element, to reflect the peaks position in the result.
So, in case of [1,2,1,2,4,5]:
count_peaks([1,2,1,2,4,5])
#=>[False, True, False, False, False, True]
Just return sum(res) instead to get the desired result: 2
It seems like you're just starting with python. Your code is difficult to follow. There are many possible solutions for this problem but I'd advise to write simple code. Then worry about performance.
Readability first!
from typing import List
def peaks(lst: List[int]):
found = 0
for i, current_value in enumerate(lst):
is_first_object = i == 0
is_last_object = i == len(lst) - 1
if is_first_object:
previous_val = None
else:
previous_val = lst[i-1]
if is_last_object:
next_val = None
else:
next_val = lst[i+1]
if is_first_object and not is_last_object:
found += 1 if current_value > next_val else 0
elif is_last_object and not is_first_object:
found += 1 if current_value > previous_val else 0
elif not is_last_object and not is_last_object:
found += 1 if previous_val < current_value > next_val else 0
return found
print(peaks([1, 2, 3]))
you can add proxy value of first element and second last element, at front and last and then check the condition from the first element to second last element
def peaks(array):
if len(array)<2:
return 0
array2 = [array[1]] + array + [array[-2]]
count = sum([1 for i in range(len(array2)-2) if array2[i+2]<array2[i+1] >array2[i]])
return count
try this one
def peaks(lst):
num = 0
leni = len(lst)
for i in range(leni):
if i == 0:
if lst[i] > lst[i+1]:
num = num + 1
elif i == leni-1:
if lst[i] > lst[i-1]:
num = num + 1
else:
if lst[i] > lst[i-1] and lst[i] > lst[i+1]:
num = num + 1
return num
Should do the trick
def peaks(lst):
lst_len = len(lst)
hits = 0
for i in range(1,lst_len-1):
num_to_test = lst[i]
before = lst[i-1]
after = lst[i+1]
if num_to_test > before and num_to_test > after:
hits+=1
# This is for the case lst contains only 1 member and you want to count it as 1
if lst_len == 1:
hits+=1
# For checking the edges
if lst_len > 1:
if lst[0] > lst[1]:
hits+=1
if lst[lst_len-1] > lst[lst_len-2]:
hits+=1
return hits
Counting of direct-neighbor peaks can be a performance-relevant task and the list of implementations is getting longer. Good reasons to compare the runtime. In a first run, I decided to go for one test set only. Obviously, the different implementations may reveal their strength at different lengths of lists. For instance, the optimal implementation of border value handling seems to be a candidate that depends on the list length.
Output:
count_peaks_schwobaseggl: elapsed time 1.44 s
count_peaks_sahasrara62: elapsed time 1.50 s
count_peaks_saikat: elapsed time 2.27 s
count_peaks_tom_wojcik: elapsed time 4.11 s
count_peaks_igian: elapsed time 3.65 s
count_peaks_cloud_balancing: elapsed time 1.86 s
Implementation:
import random
import time
from typing import List
def measure_runtime_in_s(func, test_lists):
start = time.time()
results = []
for test_list in test_lists:
max_cnt = func(test_list)
results.append(max_cnt)
return time.time() - start, results
def run_experiment(funcs, nlists=1000, len_range=(20, 10000), num_range=(-100, 100)):
assert len(funcs) > 0
# generate test data
test_lists = [[random.randint(*num_range) for _ in range(random.randint(*len_range))]
for _ in range(nlists)]
# run it for all implementations and check results
_, ref_results = measure_runtime_in_s(funcs[0], test_lists)
for func in funcs:
failed = False
time_in_s, results = measure_runtime_in_s(func, test_lists)
if not all(result == ref_result for result, ref_result in zip(results, ref_results)):
failed = True
print(
f"{func.__name__}: elapsed time {time_in_s:.2f} s"
+ (" (FAILED TESTS!)" if failed else ""))
def count_peaks_schwobaseggl(lst):
lst = [float("-inf")] + lst + [float("-inf")]
return sum(a < b > c for a, b, c in zip(lst, lst[1:], lst[2:]))
def count_peaks_sahasrara62(array):
if len(array) < 2:
return 0
array2 = [array[1]] + array + [array[-2]]
count = sum([1 for i in range(len(array2) - 2) if array2[i + 2] < array2[i + 1] > array2[i]])
return count
def count_peaks_saikat(lst):
num = 0
leni = len(lst)
for i in range(leni):
if i == 0:
if lst[i] > lst[i + 1]:
num = num + 1
elif i == leni - 1:
if lst[i] > lst[i - 1]:
num = num + 1
else:
if lst[i] > lst[i - 1] and lst[i] > lst[i + 1]:
num = num + 1
return num
def count_peaks_igian(ls):
res = [ls[0] > ls[1], ls[-1] > ls[-2]]
for n in range(len(ls)-2):
a, b, c = ls[n:n+3]
res.insert(-1, b > max([a, c]))
return sum(res) # < modified
def count_peaks_tom_wojcik(lst: List[int]):
found = 0
for i, current_value in enumerate(lst):
is_first_object = i == 0
is_last_object = i == len(lst) - 1
if is_first_object:
previous_val = None
else:
previous_val = lst[i-1]
if is_last_object:
next_val = None
else:
next_val = lst[i+1]
if is_first_object and not is_last_object:
found += 1 if current_value > next_val else 0
elif is_last_object and not is_first_object:
found += 1 if current_value > previous_val else 0
elif not is_last_object and not is_last_object:
found += 1 if previous_val < current_value > next_val else 0
return found
def count_peaks_cloud_balancing(lst):
lst_len = len(lst)
hits = 0
for i in range(1, lst_len - 1):
num_to_test = lst[i]
before = lst[i - 1]
after = lst[i + 1]
if num_to_test > before and num_to_test > after:
hits += 1
# This is for the case lst contains only 1 member and you want to count it as 1
if lst_len == 1:
hits += 1
# For checking the edges
if lst_len > 1:
if lst[0] > lst[1]:
hits += 1
if lst[lst_len - 1] > lst[lst_len - 2]:
hits += 1
return hits
if __name__ == "__main__":
run_experiment([
count_peaks_schwobaseggl,
count_peaks_sahasrara62,
count_peaks_saikat,
count_peaks_tom_wojcik,
count_peaks_igian,
count_peaks_cloud_balancing,
])
I have a string pizzas and when comparing it to pizza - it is not the same. How can you make a program that counts common letters (in order) between two words, and if it's a 60% match then a variable match is True?
For e.g. pizz and pizzas have 4 out of 6 letters in common, which is a 66% match, which means match must be True, but zzip and pizzasdo not have any letters in order in common, thus match is False
You can write a function to implement this logic.
zip is used to loop through the 2 strings simultaneously.
def checker(x, y):
c = 0
for i, j in zip(x, y):
if i==j:
c += 1
else:
break
return c/len(x)
res = checker('pizzas', 'pizz') # 0.6666666666666666
def longestSubstringFinder(string1, string2):
answer = ""
len1, len2 = len(string1), len(string2)
for i in range(len1):
match = ""
for j in range(len2):
if (i + j < len1 and string1[i + j] == string2[j]):
match += string2[j]
else:
if (len(match) > len(answer)): answer = match
match = ""
return answer
ss_len = len(longestSubstringFinder("pizz", "pizzas"))
max_len = max(len("pizza"),len("pizzas"))
percent = ss_len/max_len*100
print(percent)
if(percent>=60):
print("True");
else:
print("False")
Optimised algorithm using dynamic programming:
def LCSubStr(X, Y, m, n):
LCSuff = [[0 for k in range(n+1)] for l in range(m+1)]
result = 0
for i in range(m + 1):
for j in range(n + 1):
if (i == 0 or j == 0):
LCSuff[i][j] = 0
elif (X[i-1] == Y[j-1]):
LCSuff[i][j] = LCSuff[i-1][j-1] + 1
result = max(result, LCSuff[i][j])
else:
LCSuff[i][j] = 0
return result
This will directly return the length of LCS.
I'm trying to implement quicksort in Python based on pseudocode I read in class but it does not sort the list. It does the recursion and always returns the result of the first recursive call (which is not sorted). Could anyone explain what I'm doing wrong?
def quick_sort(S):
n = len(S)
if n < 2:
return
p = S[0]
L = []
E = []
G = []
for i in range(0,len(S)):
if S[i] < p:
L.append(S[i])
elif p < S[i]:
G.append(S[i])
else:
E.append(S[i])
quick_sort(L)
quick_sort(G)
S=L+E+G
You don't return anything, you only create new lists, but don't use them.
Return the new list:
def quick_sort(S):
n = len(S)
if n < 2:
return S
p = S[0]
L = []
E = []
G = []
for v in S:
if v < p:
L.append(v)
elif p < v:
G.append(v)
else:
E.append(v)
return quick_sort(L) + E + quick_sort(G)
print quick_sort([6,4,2,3])
I recently asked this question and got the first answer. I'm trying to put this into python code. This is what I have, but I keep getting 0 as the answer.
def f(n, k, s):
ans = 0
for j in range(1, min({k,s}) + 1):
print j
if (n == 1):
if (k >= s):
ans = ans + 1
elif (k < s):
ans = ans + 0
elif (s > n):
ans = ans + 0
elif (n*k < s):
ans = ans + 0
else:
ans = ans + f(n-1,j,s-j)
return ans
print f(10, 12, 70)
What is wrong with my code? What do I need to change? I don't know what's wrong. Please help. Thanks!
Your code is way too complex. You can write an almost one-to-one transcription of the answer you got on math exchange:
def f(n, k, s):
if n == 1:
return int(k >= s)
# or: 1 if k >=s else 0
return sum(f(n-1, j, s-j) for j in range(1, min(k, s)+1))
# to make it faster:
#return sum(f(n-1, j, s-j) for j in range(1, min(k, s)+1) if n*k >= s)
The problem in your code is that you put the base-case checking inside the loop, when it should be outside:
def f(n, k, s):
ans = 0
if n == 1:
return int(k >= s)
for j in range(1, min({k,s}) + 1):
print j
if n*k >= s:
ans += f(n-1,j,s-j)
return ans
With both implementations I get 12660 as result for f(10, 12, 70).
I don't know why yours doesn't work, but here's an implementation that does, which IMO is MUCH more readable:
from itertools import permutations
def f(n, k, s):
if k > s:
k = s-1
count = 0
sum_perms = []
number_list = []
for i in range(1,k):
for j in range(1,k,i):
number_list.append(i)
for perm in permutations(number_list, n):
if sum(perm) == s and perm not in sum_perms:
sum_perms.append(perm[:])
count += 1
return sum_perms, count
It's a lot slower than the recursion technique though :-(
itertools is amazing.