Reputation: 225
Problem:
Write a program that will search a list to find the first odd number. If an odd number is found, then find the first even number following the odd number. Return the distance between the first odd number and the first even number. Return -1 if no odd numbers are found or there are no even numbers following an odd number.
My Code:
def go(list1):
dist = 0
odd = 0
even = 0
for i in range(0,len(list1)):
if list1[i] % 2 == 1:
odd = list1[i]
break
else:
odd = list1[0]
list2 = list1[list1.index(odd)+1:]
for i in range(0,len(list2)):
if list2[i] % 2 == 0:
even = list2[i]
break
else:
even = list2[0]
return list2.index(even) + list1.index(odd) + 1 - list1.index(odd)
print(go([7,1,5,3,11,5,6,7,8,9,10,12345,11]))
print(go([11,9,8,7,6,5,4,3,2,1,-99,7]))
print(go([10,20,30,40,5,41,31,20,11,7]))
print(go([32767,70,4,5,6,7]))
print(go([2,7,11,21,5,7]))
print(go([7,255,11,255,100,3,2]))
print(go([9,11,11,11,7,1000,3]))
print(go([7,7,7,11,2,7,7,11,11,2]))
print(go([2,4,6,8,8]))
My Output:
6
2
3
1
1
4
5
4
1
Desired Output:
6
2
3
1
-1
4
5
4
-1
What am I doing wrong? Is there a better approach to this problem than what I have done?
Upvotes: 3
Views: 708
Reputation: 89
There are multiple mistakes in your code, that together contribute to the fact that your code will never return -1. It will even throw ValueError
in case you pass in an empty list.
The first problem is that you assign odd = list1[0]
in case you don't find an odd number. This is wrong in the case when there is no odd number. Then list2
will contain everything apart from the first number in list1
. Same goes, for assigning even = list2[0]
in case there is no even number after the first odd one.
Your function is correct in case there is a pair of numbers you are looking for. Though, your return statement can be simplified to list2.index(even)+1
.
Also, in python you can loop over a list using for x in lst
statement. In case you want to have access to the index of the element you are currently looking at use enumerate
like this
for i, x in enumerate(lst)
Finally, here is a nicest simple way to solve your problem I can think of that requires only one iteration of the list.
def go(lst):
odd_index = -1 # Index of the first odd number in the list
for i, n in enumerate(lst):
if n % 2 == 1:
# n is odd
if odd_index == -1:
# This is the first even number we found, so we assign
# its index to odd_index and look for an even number
odd_index = i
else:
# n is even
if odd_index != -1:
# We already found odd number, so this is the
# first even number and we can return
return i - odd_index
# The search was not successful, so we return -1
return -1
Upvotes: 0
Reputation: 43146
You could approach this with an iterator.
An iterator is an object that "remembers" its current position in the list. When the iterator is created, it points to the first element in the list. You can then move the iterator forward with the next
function.
So the idea is this:
In step 3, the enumerate
function is very useful for counting how many elements the iterator has skipped.
def go(iterable):
# step 1: get an iterator for this iterable
itr = iter(iterable)
try:
# step 2: advance the iterator to the first odd number
next(num for num in itr if num % 2 == 1)
# step 3: count the elements up to the next even number
return next(i for i, num in enumerate(itr, 1) if num % 2 == 0)
except StopIteration:
# StopIteration is raised if the iterator reaches the end without
# finding a suitable number
return -1
Upvotes: 5
Reputation: 18821
Your errors are:
list1.index(odd)
(just remove this part and the equation is correct)Instead of storing the values and creating a new list, you should store the positions:
def go(list1):
odd = None
even = None
for i in range(0,len(list1)):
if list1[i] % 2 == 1:
odd = i
break
if odd is not None:
for i in range(odd, len(list1)):
if list1[i] % 2 == 0:
even = i
break
if odd is None or even is None:
return -1
else:
return even - odd
And here's a more pythonic version:
def go(list1):
try:
odd = next(i for (i, v) in enumerate(list1) if v % 2 == 1)
even = next(i for (i, v) in enumerate(list1) if v % 2 == 0 and i > odd)
return even - odd
except StopIteration:
return -1
StopIteration
is an exception raised when next reaches the end of the list without any matching value.
Upvotes: 4
Reputation: 501
This is similar to what other commenters have suggested by storing the index of the even and odd numbers:
def go(list1):
dist = 0
odd_idx = None
even_idx = None
for i in range(len(list1)):
if list1[i] % 2 == 1:
odd_idx = i
break
if odd_idx is None:
return -1
list2 = list1[odd_idx+1:]
for i in range(len(list2)):
if list2[i] % 2 == 0:
even_idx = i
break
if even_idx is None:
return -1
return abs(even_idx - odd_idx + 1)
print(go([7,1,5,3,11,5,6,7,8,9,10,12345,11]))
print(go([11,9,8,7,6,5,4,3,2,1,-99,7]))
print(go([10,20,30,40,5,41,31,20,11,7]))
print(go([32767,70,4,5,6,7]))
print(go([2,7,11,21,5,7]))
print(go([7,255,11,255,100,3,2]))
print(go([9,11,11,11,7,1000,3]))
print(go([7,7,7,11,2,7,7,11,11,2]))
Hope this helps!
Upvotes: 0
Reputation: 11878
I would do something like this:
def go(list1):
dist = 0
found = False;
for i in range(0,len(list1)):
if list1[i] % 2 == 1:
for j in range(i,len(list1)):
if list1[j] % 2 == 0:
found = True;
return(j-i)
break
if(found == False):
return -1;
print(go([7,1,5,3,11,5,6,7,8,9,10,12345,11]))
print(go([11,9,8,7,6,5,4,3,2,1,-99,7]))
print(go([10,20,30,40,5,41,31,20,11,7]))
print(go([32767,70,4,5,6,7]))
print(go([2,7,11,21,5,7]))
print(go([7,255,11,255,100,3,2]))
print(go([9,11,11,11,7,1000,3]))
print(go([7,7,7,11,2,7,7,11,11,2]))
print(go([2,4,6,8,8]))
The main problem in your code I see is that you default to the first element in the list instead of defaulting to -1 if odd or even isn't found. You never check to see if its not found.
I added a boolean in my code that checks if we have found the element yet. The code works without the boolean altogether but I added it to show that we want to be checking to see if we have found the odd and even element yet or not. If we don't find it: we return -1. Otherwise: we return the difference.
Upvotes: 0
Reputation: 1140
Answering what is wrong I think it the use of your 'else ' statements:
else:
even = list2[0]
Why are you assigning a number from the list if you do not find any even? That is why your distance is = 1
Same thing for :
else:
odd = list1[0]
You shouldn't assign a number to odd, if you do not find one.
Upvotes: 0