0
votes

I have written a function which, when given a list of integers, returns True when the list argument contains a 3 next to a 3 somewhere. Here is my code:

def has_33(nums):
    for i,num in enumerate(nums):
        if nums[0]==3 and nums[1]==3:
            return True
        elif nums[i+1]==3 and (nums[i+2]==3 or nums[i]==3):
            return True
        else:
           return False 

This function either returns True or False even though I realised

nums[i+1]

could be out of range when the loop reaches the last index.

E.g if I have a list defined as nums=[1,3,4,5], the function returns False. However, when I separately run

nums[4]==1

I get "IndexError: list index out of range" which I understand why but I don't understand why, in the function,

nums[i+1] or (nums[i+2] or nums[i]==3)

doesn't throw the same error when it reaches the last index of the list?

2
You never finish the loop, you are returning false in your first iteration.Loocid
Just for fun a different approach: return '3,3' in ','.join(str(v) for v in nums)Matthias
@Matthias Just for fun, you don't need the ,ChatterOne
@ChatterOne You do, or else [33,1,2,4,5,6] would return true :)Loocid
@Loocid Yes, isn't that what we're looking for?ChatterOne

2 Answers

1
votes

The function does not throw the IndexError because it never reaches the last element of the list.

In the first iteration if evaluates condition 1 and 2, both are false so it goes into the else returning False, and no more iterations are performed.

If you try with nums = [1, ] you actually get the IndexError. The beahavior you are looking for is achieved moving return False outside the loop:

def has_33(nums):
    for i, num in enumerate(nums):
        if nums[0]==3 and nums[1]==3:
            return True
        elif nums[i+1]==3 and (nums[i+2]==3 or nums[i]==3):
            return True
    return False   # <- this is outside the for loop

This way it cycles every element in the nums list. However you are right saying that your code will throw an IndexError every time the list do not contain a pair of 3's. A safer way would be to skip the first iteration and look for the element and its previous. A safer an more pythonic way would be to use the zip function in one line of code (I don't want to spoil the solution, if interested reply with a comment).

-2
votes

Loop through the list and just check if there is a '3' at index i and i+1. You need to be sure you loop till (length of list -1), so that there won't be any indexoutofrange exception when you access i+1.

def has_33(nums):
    for i in range(len(nums)-1):
       if(nums[i]==3 and nums[i+1]== 3):
        return True
    return False

print(has_33([3,3,3,4,5,3,3,4]))