Python code explanation need - python

def array_front9(nums):
end = len(nums)
if end > 4:
end = 4
for i in range(end):
if nums[i]==9:
return True
return False
I need to understand the above python code and why two return statement in 'for loop'. This is seriously confusing me.

This could be rewritten much simpler (that is, "more pythonic") as this:
def array_front9(nums):
return 9 in nums[:4]
The first half of the code is setting the loop limit to the first 4 elements, or less if the array nums is shorter. nums[:4] does essentially the same thing by creating a copy that only contains up to the first 4 elements.
The loop is checking to see if the element 9 is found in the loop. If found, it returns immediately with True. If it's never found, the loop will end and False is returned instead. This is a longhand form of the in operator, a built-in part of the language.

Let me explain:
def array_front9(nums): # Define the function "array_front9"
end = len(nums) # Get the length of "nums" and put it in the variable "end"
if end > 4: # If "end" is greater than 4...
end = 4 # ...reset "end" to 4
for i in range(end): # This iterates through each number contained in the range of "end", placing it in the variable "i"
if nums[i]==9: # If the "i" index of "nums" is 9...
return True # ...return True because we found what we were looking for
return False # If we have got here, return False because we didn't find what we were looking for
There are two return-statements in case the loop falls through (finishes) without returning True.

The second return isn't in the for loop. It provides a return value of False if the loop "falls through", when none of nums[i] equal 9 in that range.
At least, that's how you've indented it.

You could rewrite this to be more clear using list slicing:
def array_front9(nums):
sublist = nums[:4]
if 9 in sublist:
return True
else:
return False

Related

Python noob question. Looping through all to find correct combination

Sorry for noob question. Just started learning coding with Python - beginners level.
Wasn't able to find in the net what I require.
Creating function to loop through the entire line, in order to find right combination - 7,8,9 - regardless of input length and of target position, and return 'true' if found. Wasn't able to devise the function correctly. Not sure how to devise function clearly and at all this far.
Your help is much appreciated.
This is what I came up with so far (not working of course):
def _11(n):
for loop in range(len(n)):
if n[loop]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
It always returns False. Tried with (*n) to no avail.
The answer offered by #Carson is entirely correct.
I offer this not really as an answer to the question but as an alternative and more efficient approach.
In OP's question he is looking for an occurrence of 3 consecutive values described by way of a list. Let's call that a triplet.
If we iterate over the input list one element at a time we create lots of triplets before comparing them.
However, we can make this more efficient by searching the input list for any occurrence of the first item in the target triplet. In that way we are likely to slice the input list far less often.
Here are two implementations with timings...
from timeit import timeit
def _11(n, t):
offset = 0
lt = len(t)
m = len(n) - lt
while offset < m:
try:
offset += n[offset:].index(t[0])
if n[offset:offset+lt] == t:
return True
offset += 1
except ValueError:
break
return False
def _11a(n, t):
for index in range(len(n) - len(t)):
if n[index:index + len(t)] == t:
return True
return False
n = [1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]
t = [7, 8, 9]
for func in _11, _11a:
print(func.__name__, timeit(lambda: func(n, t)))
Output:
_11 0.43439731000012216
_11a 1.8685798310000337
There are two mistakes with your code.
Indexing into a loop returns 1 element, not multiple. When you write n[loop], you're getting 1 value, not a list.
You shouldn't return false that early. Your code exits after the first step in the loop, but it should go through the entire loop before returning false.
Consider the following snippet:
def has_subarr(arr, subarr):
"""Tests if `subarr` exists in arr"""
for i in range(len(arr)):
if arr[i:i+len(subarr)] == subarr:
return True
return False
This code is more general than your example, it accepts the value to check for as another argument. Notice the use of : in the array access. This allows you to return multiple elements in an array. Also notice how the return False is only reached once the entire loop has completed.
First, n[loop] return a single element, not a sublist. You should use n[loop+3]. But this will introduce a problem where loop+3 exceeds the length of the list. So the solution may be:
def _11(n):
for loop in range(len(n)-3):
if n[loop:loop+3]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
Your actual code return during the first iteration. You only test once. You must modify the indentation as in:
def _11(n):
target = [7,8,9]
for index in range( len(n) - len(target)):
if n[index:index + len(target)] == [7,8,9]:
return True
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
You can try checking the str representation of the 2 lists:
import re
def _11(n):
if re.search("(?<![0-9-.'])7, 8, 9(?![0-9.])",str(n)):
return True
return False
print(_11([27,8,9]))
The Output:
False

function that uses a while loop to return characters in a list while also being subject to other conditions

To preface, because I’m learning to use while loops, I want to write this function with only if statements, in statements, and while loops. I think I may also need to use break or continue. I don’t want to use for loops or forms of list comprehension.
the function itself should looks like take_last(lst)
It should normally take in a list of words and returns the last value in the list with the first and last characters of it removed.
for instance,
take_last[“Fish”, “Meat”, “Fruit”, “Cake”]
will return “ak” as this is the last word in the list with the characters, “C” and “e” removed. This part of the function is relatively simple. I think it can be done with
return (lst[-1])[slice(1,-1)]
However, it is subject to two different conditions that may make writing the function difficult.
if the first name in the list has less than 3 characters, the function will stop and return “finished”
i.e take_list([“SH”, “Meat”]) will stop at “SH” and instead returns “finished”.
otherwise, if this condition is not fulfilled and the first word has 3 or more characters, the function will continue iterating through the list until it finds another word with less than 3 characters. it will then stop at this point and return the previous character in the list with the first and last character in it removed.
I.e if the input is take_last([“Fish”, “Meat”, “Fruit”, “SH”, “Cake”]) the function breaks at “SH” and instead “rui” is returned. (Fruit without the ‘F
What I am Trying
Although I am not sure how to structure the while loop, I have written the function with the first condition already fulfilled.
def take_last(lst):
if len(lst[0]) < 3:
return "finished"
else:
return (lst[-1])[slice(1,-1)]
take_last([“Fish”, “Meat”, “Fruit”, “Cake”]) will return “ake”
and take_last([“Fi”, “Meat”, “Fruit”, “Cake”]) will return
“finished”
I know that somewhere in my function I will need an elif statement followed by a while loop but I’m not sure how this would look. Any help would be appreciated.
Here's a simple way to do it.
def take_last(lst):
i = 0
while i < len(lst) and len(lst[i]) >= 3:
i += 1
if i == 0:
return "finished"
else:
return lst[i-1][1:-1]
The while loop repeats as long as the string at index i is at least 3 characters long. So when it's done, i contains the index of the first short string; if there are no short elements, it will contain the length of the list.
If the first string is short, i will be 0, so there's no element before it and we return finished.
Otherwise we return the slice of the element before i. This will be the last element when there are no short elements.
So returning the last word with 1st and 3rd chars removed is the last possible thing we can do. There may be conditions before it which may cause the the function to stop early.
So, now we know what becomes our default return
return (lst[-1])[slice(1,-1)]
Similarly, the first condition you are checking is correct as well. So that fixes our starting if.
if len(lst[0]) < 3:
return "finished"
Now the condition 2. We can tackle this in the else clause. We need to iterate through the list looking for a word less than 3 chars. If we find it, we return the element just before it after truncation .
else:
i = 1
while (i < len(lst)):
if len(lst[i]) < 3:
return (lst[i-1])[slice(1,-1)]
i += 1
Everything put together:
def take_last(lst):
if len(lst[0]) < 3:
return "finished"
else:
i = 1
while (i < len(lst)):
if len(lst[i]) < 3:
return (lst[i-1])[slice(1,-1)]
i += 1
return (lst[-1])[slice(1,-1)]
You can easily do this with a regular for loop in a way that, to me, feels a lot more natural than doing it with a while loop:
def take_last(lst):
prev = None
for val in lst:
if len(val) < 3:
break
prev = val
if prev is None:
return "finished"
else:
return prev[1:-1]

Would this be the correct way to search from the end of a Python list using a function?

Suppose we have this function:
def search(ls, e):
'''Assumes ls is a list.
Returns True if e is in ls, False otherwise.'''
for i in reversed(range(len(ls))):
if ls[i] == e:
return True
return False
I'm trying to get this function to search through ls starting from the end of the list instead of the beginning. Hence, I included reversed(), which reverses the list, ls.
However, what I'm specifically trying to do is search a list but instead of starting from the index of 0, starting from the index of -1. I don't think reversed() technically does this? If not, how could the function be modified to achieve my objective?
list1 = [1,2,3,4,5]
for i in reversed(range(len(list1))):
print(list1[i])
5
4
3
2
1
it does exactly what you want no?
l2 = [1,2,3,4,5]
for i in range(len(l2)):
print(l2[-i-1])
5
4
3
2
1
you could try something like:
for i in range(len(ls)):
if ls[(-1)*i] == e:
return True
return False
It should start at the back of the list and move forward.
I would actually use enumerate() to do the heavy lifting for you. Using print statements instead of return you can see how it is working better. Basically it creates a physical location index, 0 through the length of the list and allows you to iterate through both the values and the indexes. We do not need the indexes for this, but you have both.
x = [1,2,3,4,5]
for index, value in enumerate(reversed(x)):
if value== 2:
print("TRUE")
else:
print("FALSE")
This first reverses the list, creates enumerated indices and values, assigns the indices iteratively to index and each value (which can be anything a string, a float, another list)to the variable value and in the if else statement compares it to the value (which would be s in your function)
The output is:
FALSE
FALSE
FALSE
TRUE
FALSE
You can see it counted backwards toward 1. I makes seeing what is happening more explicit and allows you to use both the values and the index values of the reversed list without having to slice the original list and keep track of direction.

Count the number of times each element appears in a list. Then making a conditional statement from that

write a function that takes, as an argument, a list called aList. It returns a Boolean True if the list contains each of the integers between 1 and 6 exactly once, and False otherwise.
This is homework and I thought I had it right, but it is now telling me that it isn't right. Here is my code.
def isItAStraight(aList):
count = 0
for i in set(aList):
count += 1
return aList.count(i) == 1
for some reason even if a number appears more than once it still gives true and I can't figure out why it won't give me false unless the first or last number are changed.
Each number has to occur only one time otherwise it is false.
So like take [1,2,3,4,5,6]
would be true.
But [1,2,2,3,4,5]
would be false.
Also, I can't import things like Counter or collections (though it would be so much easier to do it isn't apart of the assignment.)
The list is randomly generated from 1 to 6.
With a return inside the loop, you are only checking one value. You need to check each value. Also, instead of looping through the items of the list, you should loop through the items you're actually looking for. It would also help to make sure there are the correct number of items in the list.
def isItAStraight(aList):
if len(aList) != 6:
return False
for i in range(1, 7):
if aList.count(i) != 1:
return False
return True
But the easiest way to do this is to simply sort the list and check if it's what you're looking for:
def isItAStraight(aList):
return sorted(aList) == list(range(1, 7))
You need to be careful about what's inside the list. What you've written is a basically the same as the pseudo-code below:
let count = 0
for every unique element in aList:
Add 1 to count
if count is now 1, return true.
This will always return true if there is at least one element in aList, since you're adding 1 to count and then returning immediately.
A couple approaches to consider:
Create a 6 element list of all zeros called flags. Iterate over aList and set the corresponding element in flags to 1. If flags is all ones, then you return true.
Sort the list, then check if the first six numbers are 1, 2, 3, 4, 5, 6.

In this short recursive function `list_sum(aList)`, the finish condition is `if not aList: return 0`. I see no logic in why this condition works

I am learning the recursive functions. I completed an exercise, but in a different way than proposed.
"Write a recursive function which takes a list argument and returns the sum of its integers."
L = [0, 1, 2, 3, 4] # The sum of elements will be 10
My solution is:
def list_sum(aList):
count = len(aList)
if count == 0:
return 0
count -= 1
return aList[0] + list_sum(aList[1:])
The proposed solution is:
def proposed_sum(aList):
if not aList:
return 0
return aList[0] + proposed_sum(aList[1:])
My solution is very clear in how it works.
The proposed solution is shorter, but it is not clear for me why does the function work. How does if not aList even happen? I mean, how would the rest of the code fulfill a not aList, if not aList means it checks for True/False, but how is it True/False here?
I understand that return 0 causes the recursion to stop.
As a side note, executing without if not aList throws IndexError: list index out of range.
Also, timeit-1million says my function is slower. It takes 3.32 seconds while the proposed takes 2.26. Which means I gotta understand the proposed solution.
On the call of the function, aList will have no elements. Or in other words, the only element it has is null. A list is like a string or array. When you create a variable you reserve some space in the memory for it. Lists and such have a null on the very last position which marks the end so nothing can be stored after that point. You keep cutting the first element in the list, so the only thing left is the null. When you reach it you know you're done.
If you don't use that condition the function will try to take a number that doesn't exist, so it throws that error.
You are counting the items in the list, and the proposed one check if it's empty with if not aList this is equals to len(aList) == 0, so both of you use the same logic.
But, you're doing count -= 1, this has no sense since when you use recursion, you pass the list quiting one element, so here you lose some time.
According to PEP 8, this is the proper way:
• For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
Here is my amateur thougts about why:
This implicit check will be faster than calling len, since len is a function to get the length of a collection, it works by calling an object's __len__ method. This will find up there is no item to check __len__.
So both will find up there is no item there, but one does it directly.
not aList
return True if there is no elements in aList. That if statement in the solution covers edge case and checks if input parameter is not empty list.
For understand this function, let's run it step by step :
step 0 :
L=[0,1,2,3,4]
proposed_sum([0,1,2,3,4])
L != []
return l[0] + proposed_sum([1,2,3,4])
step 1 calcul proposed_sum([1,2,3,4]):
proposed_sum([1,2,3,4])
L != []
return l[0] + sum([2,3,4])
step 2 calcul proposed_sum([2,3,4]):
proposed_sum([2,3,4])
L != []
return l[0] + sum([3,4])
step 3 calcul proposed_sum([3,4]):
proposed_sum([3,4])
L != []
return l[0] + sum([4])
step 4 calcul proposed_sum([4]):
proposed_sum([4])
L != []
return l[0] + sum([])
step 5 calcul proposed_sum([]):
proposed_sum([])
L == []
return 0
step 6 replace:
proposed_sum([0,1,2,3,4])
By
proposed_sum([]) + proposed_sum([4]) + proposed_sum([3,4]) + proposed_sum([2,3,4]) + proposed_sum([1,2,3,4])+ proposed_sum([0,1,2,3,4])
=
(0) + 4 + 3 + 2 + 1 + 0
Python considers as False multiple values:
False (of course)
0
None
empty collections (dictionaries, lists, tuples)
empty strings ('', "", '''''', """""", r'', u"", etc...)
any other object whose __nonzero__ method returns False
in your case, the list is evaluated as a boolean. If it is empty, it is considered as False, else it is considered as True. This is just a shorter way to write if len(aList) == 0:
in addition, concerning your new question in the comments, consider the last line of your function:
return aList[0] + proposed_sum(aList[1:])
This line call a new "instance" of the function but with a subset of the original list (the original list minus the first element). At each recursion, the list passed in argument looses an element and after a certain amount of recursions, the passed list is empty.

Categories