I wrote a code in Python that print a Fibonacci sequence truncated at a given threshold.
m_char=input('threshold: ')
m=int(m_char)
def fibonacci(m):
lst=[0, 1]
while lst[-1] <= m:
a = lst[-2]+lst[-1]
if a <= m:
lst.append(a)
else:
print(lst)
return
fibonacci(m)
I don't like the double check on the variable m in the while and if statement: I'm pretty sure it is redundant, so there is a way to write more efficient code. I would like to preserve the use of lists. Have you got any idea?
def fibonacci(m):
lst=[0, 1]
a = lst[-2]+lst[-1]
while a <= m:
lst.append(a)
a = lst[-2]+lst[-1]
return lst
You can calculate a once per loop, and use it to determine the whether the loop continues
Just use
while True:
it is the check inside the loop which actually determines how often the loop is run.
It would be slightly more efficient to not use list indexing at all but instead maintain the last two Fibonacci numbers with two variables. Furthermore, it is more idiomatic to return the list rather than print it. Let the calling code print the list if it wants:
def fibonacci(m):
lst=[0, 1]
a,b = lst
while True:
a,b = b, a+b
if b <= m:
lst.append(b)
else:
return lst
Related
I am new to python and I have to do an exercise for classes. The exercises asks me to make a function which tells weather a list given is ordered decreasing or not (Giving back True or False)
I tried the following code:
def no_decreasing(list):
for num in len(list):
if list[num] <= list[num+1]:
check = bool(1)
else:
check = bool(0)
break
return check
It gives back an te error "int" object is not iterable in line 2, does anyone know why?
Note: don't use list as the parameter name (it's a builtin type), use something else. I'll use nums as the place of the list parameter rather than list.
The expression for num in len(nums) doesn't work because len(nums) is a single int. What you would want instead is for num in nums (which would iterate over each number in nums, or for index in len(range(nums)) (which would iterate over each valid index into nums).
Other options:
for i, num in enumerate(nums) -- i is the index, num is the value.
for num1, num2 in zip(nums, nums[1:]) -- num1 and num2 are two successive values from nums, obtained by zipping nums with a shifted version of itself.
Additional note: when you need a boolean literal, instead of bool(1) and bool(0) just use True and False!
You could also shortcut the entire problem by sorting the list in decreasing order and seeing if it's the same as the original list:
def is_decreasing(nums):
return nums == sorted(nums, reverse=True)
Well you are trying to iterate over indeces, so
for i in range(len(lst)): # never use "list" as a variable name
or rather
for i in range(len(lst)-1): # to avoid an index error for its right neighbor
would be appropriate. However, a better way would use zip
def non_decreasing(lst):
for a, b in zip(lst, lst[1:]):
if b < a:
return False
return True
A short-hand for that pattern is any or all:
def non_decreasing(lst):
return all(a <= b for a, b in zip(lst, lst[1:]))
# return not any(b < a for a, b in zip(lst, lst[1:]))
You are trying to get the index in the for loop, but you've made a semantic mistake:
for num in len(list):
# This does not work. It can not iterate through an integer.
len() function returns an integer. Your basically saying for num in 10, say if the list has 10 numbers.
What you want is the range function:
for num in range(0, len(list)):
This will loop from num=0 to num=0+len(list)-1.
Be careful though with if list[num] <= list[num+1]:, as the previous approach will make that line search for an index greater them your array size. As such, this is how you could fix your code:
for num in range(0, len(list)-1):
P.S.: There are other ways to solve that issue, but since it is a class exercise, I've focused on solving the issue you've had when iterating through an integer.
Others have pointed out using zip(lst, lst[1:]). This is undesirable for large lists, though, since you first have to make a copy of lst (minus the first element) before zip can produce the pairwise iterator that the for loop uses.
Instead, use two separate iterators, advancing the second one before passing it to zip.
def no_decreasing(lst):
i1 = iter(lst)
i2 = iter(lst)
next(i2)
return all(a >= b for a, b in zip(i1, i2))
# Or you can use map
# return all(map(operator.ge, i1, i2))
Is there any way to get the next n values of a generator without looping or calling next() n times?
The thing that the generator in this case is infinite, and cannot be translated into a list.
Here is the generator function:
def f():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
The following loops both give the desired result, but I would like to know if there is some other method of doing this.
gen = f()
n = 0
while n < 10:
print(next(gen))
n += 1
or..
for n, i in enumerate(f()):
if n < 10:
print(i)
else:
break
There are several ways to do this. One way is to use list comprehension, similar to what you already have above. For instance:
gen = f()
elements = [next(gen) for _ in range(10)]
Another way is to use something like the itertools module, for instance the takeWhile()- or islice()-function.
Also check out How to get the n next values of a generator in a list (python).
Let's say I have a string
S = "qwertyu"
And I want to build a list using recursion so the list looks like
L = [u, y, t, r, e, w, q]
I tried to write code like this:
def rec (S):
if len(S) > 0:
return [S[-1]].append(rec(S[0:-1]))
Ideally I want to append the last element of a shrinking string until it reaches 0
but all I got as an output is None
I know I'm not doing it right, and I have absolutely no idea what to return when the length of S reaches 0, please show me how I can make this work
(sorry the answer has to use recursion, otherwise it won't bother me)
Thank you very much!!!
There are many simpler ways than using recursion, but here's one recursive way to do it:
def rec (S):
if not S:
return []
else:
temp = list(S[-1])
temp.extend(rec(S[:-1]))
return temp
EDIT:
Notice that the base case ensures that function also works with an empty string. I had to use temp, because you cannot return list(S[-1]).extend(rec(S[:-1])) due to it being a NoneType (it's a method call rather than an object). For the same reason you cannot assign to a variable (hence the two separate lines with temp). A workaround would be to use + to concatenate the two lists, like suggested in Aryerez's answer (however, I'd suggest against his advice to try to impress people with convoluted one liners):
def rec (S):
if not S:
return []
else:
return list(S[-1]) + rec(S[:-1])
In fact using + could be more efficient (although the improvement would most likely be negligible), see answers to this SO question for more details.
This is the simplest solution:
def rec(S):
if len(S) == 1:
return S
return S[-1] + rec(S[:-1])
Or in one-line, if you really want to impress someone :)
def rec(S):
return S if len(S) == 1 else S[-1] + rec(S[:-1])
Since append mutates the list, this is a bit difficult to express recursively. One way you could do this is by using a separate inner function that passes on the current L to the next recursive call.
def rec(S):
def go(S, L):
if len(S) > 0:
L.append(S[-1])
return go(S[0:-1], L)
else:
return L
return go(S, [])
L = [i for i in S[::-1]]
It should work.
This is working fine but I just don't get it why this works in this way. I think the return of True value should be inside the for loop but when I run this program it works in the opposite way.
Can someone point out what i am misunderstanding about the indentation of return values?
Even though the solution was even shorter I wanted to know exactly about my way of coding. Please help!
# My attempt
def palindrome(s):
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1):
if mylist[i] == mylist[j]:
i+=1
j-=1
continue
return False
return True
# Solution answer:
def palindrome(s):
return s == s[::-1]
When a function is called, the function can return only once.
This kind of return pattern is very frequently found across various programming languages. It is intuitive and efficient.
Let's say you have to check if a list of 1000 values contain only even numbers. You loop through the list and check if each element is even. Once you find an odd number, you do not need to go further. So you efficiently and immediately return and exit from the loop.
Here is hopefully a little bit more intuitive version of your code:
def palindrome(s):
l, r = -1, 0 # left, right
for _ in range(0, len(s) // 2 + 1): # more efficient
l += 1
r -= 1
if s[l] != s[r]:
return False
return True
Once you know the input is not palindrome, you do not need to go further.
If you did not need to stop, it is palindrome.
They follow the exact same rules as any other statement. What you have written means
def palindrome(s) {
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1) {
if mylist[i] == mylist[j] {
i+=1
j-=1
continue
}
return False
}
return True
}
# My attempt
def palindrome(s):
mylist = list(s)
j = -1
for i in range(0,len(mylist)-1):
if mylist[i] == mylist[j]:
i+=1
j-=1
continue
return False
return True
In the above code what happens is inside the for loop each time it checks if there is a mismatch in the values by comparing values by iterating over the list forwards using variable "i" and backwards using variable "j". and returns false immediately if any one letter mismatches and so exits from the loop. And true is returned only once the for loop is completed which means no mismatch was found in the loop
Note: i=0 gives first index, i+=1 iterates forward and j=-1 gives last index, j-=1 iterates backward
Basically, when you index an array in numpy, you do it the way:
a[start:end:step]
,for every dimension. If step is negative, you return the values in inverse order. So, if step is -1, the array a[::-1] is the inverted array of a[::].
a[::-1] = a[::]
Then, if a sequence is the same as its inverse, by definition, it is a palindrome.
See:
https://www.geeksforgeeks.org/numpy-indexing/
def digits(n):
res = []
while n > 0:
res.append(n % 10)
n /= 10
return res
I want to rewrite this function so it uses recursion. I'm currently lost as to what to do. Can anyone give me some direction?
To create a recursive function you need to determine two things:
1) The base case - the condition on which you want to stop recursion
2) The general case - what to do on every input but the base case
You have already found both of these things, the base case is the while loop condition and the general case is the inside of the while loop. Try to use this information to move forward.
Here's a possible solution:
def digits(n):
if n < 10:
return [n]
return digits(n/10) + [n%10]
digits(123)
> [1, 2, 3]
The above solution fixes a bug in your code, you were returning the digits in reverse order. Also notice that n must be an integer greater than or equal to zero for producing correct results.
Here's how it works:
If the number is less than 10, then return a list with the number, as there are no more digits to be processed
If the number is greater than 9, get the last digit in the current number and add it to the end of the list that results of recursively calling digits on a smaller number - namely, the number without the last digit that we just processed.
The call to digits(123) will look like this at each step of the recursion:
digits(123) = digits(123/10) + [3]
digits(12) = digits(12/10) + [2]
digits(1) = [1]
Now we go up the call stack:
[1]
[1] + [2]
[1, 2] + [3]
[1, 2, 3]
EDIT :
Accepting #thg435's challenge, here's a tail-recursive solution:
def digits(n):
def loop(i, acc):
if i < 10:
return [i] + acc
return loop(i/10, [i%10] + acc)
return loop(n, [])
When you use recursion, a good basis is to have two cases to check, a base case and a recursive case. The base case is the conditions and result under which the program returns, in your case, the base case would be when n > 0 (If you think of it like a while loop, it's the condition for the while loop exiting). The recursive case (there can be multiple of these) occur when the loop isn't done, if you compare to a while loop, this is basically the body of the loop. At the end of the recursive case, you need to call the function again with your changes to the input, in this case n/10.
So, your function definition would be something like:
def digits(n):
For the base case, you want to check if n is 0, and, if it is, return the empty list:
if n <= 0:
return []
Now, in the recursive case, you want to append n%10 to the list and call your function again, only you want to call it with a different n, changed as you had it in your while loop:
else:
return [n%10]+digits(n/10)
So, if you trace this through, for every recursive case, you get a list containing n%10, then it adds the result of the new call, which will be either (n/10)%10 or the empty list. For example, running this function with n=100 would break down like this:
newlist = digits(100)
newlist = [100%10]+digits(100/10)
newlist = [100%10]+([10%10] + digits(10/10))
newlist = [100%10]+([10%10] + ([1%10] + digits(10/10)))
newlist = [100%10]+([10%10] + ([1%10] + ([])))
newlist = [0,0,1]
Nested parens are used to show how the function digits gets rewritten inline.
def digits(n):
res = []
res.append(n%10)
n /= 10
if n != 0:
return res + digits(n)
else:
return res