Contents |
CodingBat's Exercises (below):
Tutorial: |
Return the number of even ints in the given array. Note:
the % "mod" operator computes the remainder, e.g. 5 % 2 is 1. count_evens([2, 1, 2, 3, 4]) → 3 count_evens([2, 2, 0]) → 3 count_evens([1, 3, 5]) → 0 |
|
1. Straightforward answer:
def count_evens(nums): count = 0 for n in nums: if n % 2 == 0: count = count + 1 return count |
This is a straightforward application of the for in looping construct. |
2. Create a list of only the even
numbers, and return its length:
def count_evens(nums): newlist = [] for n in nums: if n%2 == 0: newlist.append(n) return len(newlist) |
|
3. Use a "list comprehension"
to do the same thing as #2:
def count_evens(nums): return len([n for n in nums if n%2 == 0]) |
This does the same thing as #2 above, except more
compactly.
The list comprehension expression: "[n for n in nums if n%2 == 0]" selects and creates a new list based on the nums list, but containing only its even elements. The len() of this new list returns the answer requested. |
4. Using reduce() and a
list comprehension
def OneIfEven(n): return (n+1)%2 def SumList(L): return reduce(lambda x,y: x+y, L, 0) def count_evens(nums): return SumList([OneIfEven(k) for k in nums]) |
Here's our strategy: create a new list of ones and zeros,
with the ones where the even numbers in nums were, and zeros
where the odd ones were. So, for instance, from [2, 1, 2, 3, 4]
create: [1, 0 , 1, 0, 1], then add up the numbers in this new list.
OneIfEven(n) will return a 1 if n is even, otherwise 0. |
5. Using .count() and a
list comprehension
def count_evens(nums): return [k%2 for k in nums].count(0) |
As in #4 above, create a new list with ones and zeros where the evens and odds were in the nums list, but this time assign a 0 for the evens, and 1 for the odds. Having created that list, use the .count() method to count the number of zeros. |
Given an array length 1 or more of ints,
return the difference between the largest and smallest values in the
array. Note: the built-in min(v1, v2) and max(v1, v2) functions return
the smaller or larger of two values. big_diff([10, 3, 5, 6]) → 7 big_diff([7, 2, 10, 9]) → 8 big_diff([2, 10, 7, 2]) → 8 |
|
1. Straightforward answer:
def big_diff(nums): # find the smallest smallest = nums[0] for n in nums: smallest = min(smallest,n) # find the largest largest = nums[0] for n in nums: largest = max(largest,n) return largest - smallest |
They give you a hint about using the functions min() and max() to compare 2 numbers.. |
2. But if we look up min()
and max()...
def big_diff(nums): return max(nums) - min(nums) |
...we'd find that they also work on entire lists! |
3. Alternatively, we could sort
the list first ...
def big_diff(nums): nums.sort() return nums[-1] - nums[0] |
It's useful to be aware of useful list methods... |
4. But if we didn't know about min(list)
and max(list) ...
def big_diff(nums): return reduce(lambda x,y: x if x>y else y,nums) - reduce(lambda x,y: x if x<y else y,nums) |
...we can create the equivalents of max(list) and min(list) using the reduce() function |
Return the "centered" average of an
array of ints, which we'll say is the mean average of the values, except
ignoring the largest and smallest values in the array. If there are
multiple copies of the smallest value, ignore just one copy, and
likewise for the largest value. Use int division to produce the final
average. You may assume that the array is length 3 or more. centered_average([1, 2, 3, 4, 100]) → 3 centered_average([1, 1, 5, 5, 10, 8, 7]) → 5 centered_average([-10, -4, -2, -4, -2, 0]) → -3 |
|
1. Straightforward answer:
def centered_average(nums): # find the smallest smallest = nums[0] for n in nums: smallest = min(smallest,n) # find the largest largest = nums[0] for n in nums: largest = max(largest,n) # find the sum sum = 0 for n in nums: sum += n return (sum - smallest - largest) / (len(nums) - 2) |
Same as "big_diff" above: using min() and max()... |
2. Knowing about min(list) and
max(list) and sum(list)...
def centered_average(nums): return (sum(nums) - min(nums) - max(nums)) / (len(nums) - 2) |
|
3. Again, creating the equivalent
of min(list), etc. using reduce()...
def smallest(L): return reduce(lambda x,y: x if x<y else y,L) def largest(L): return reduce(lambda x,y: x if x>y else y,L) def SumList(L): return reduce(lambda x,y: x+y, L) def centered_average(nums): return (SumList(nums)-smallest(nums)-largest(nums))/(len(nums)-2) |
If we didn't know about min(list) and max(list), we could create smallest(list) and largest(list) using the reduce() function, and also create the SumList(list) function that way. |
4. We can put all the helper
functions (above) directly inside our main function...
def centered_average(nums): def smallest(L): return reduce(lambda x,y: x if x<y else y,L) def largest(L): return reduce(lambda x,y: x if x>y else y,L) def SumList(L): return reduce(lambda x,y: x+y, L) return (SumList(nums)-smallest(nums)-largest(nums))/(len(nums)-2) |
The 3 helper functions are (perhaps) only needed to help us with our current task, and so the rest of the world need not know about them, and so we can hide them inside the main (centered_average()) function. And then we can use them immediately. |
Return the sum of the numbers in the array,
returning 0 for an empty array. Except the number 13 is very unlucky, so
it does not count and numbers that come immediately after a 13 also do not
count. sum13([1, 2, 2, 1]) → 6 sum13([1, 1]) → 2 sum13([1, 2, 2, 1, 13]) → 6 |
|
1. Straightforward solution...
def sum13(nums): sum = 0 pos = 0 while pos < len(nums): if nums[pos] == 13: pos += 1 else: sum += nums[pos] pos += 1 return sum |
Notice that we end up incrementing the pos variable twice if the number is 13 (thereby skipping the number right after the 13). |
2. Remove each offending 13 (and
the number right after it)
def sum13(nums): while 13 in nums: pos = nums.index(13) del nums[pos:pos+2] # remove the 13 and the number after it # now add up the numbers that remain in the list sum = 0 for n in nums: sum += n return sum |
|
3. Create a helper function telling
us whether to add or not..
def sum13(nums): def NoAdd(L,i): if L[i] == 13: return True if i > 0 and L[i-1] == 13: return True return False sum = 0 pos = 0 while pos < len(nums): if not NoAdd(nums,pos): sum += nums[pos] pos += 1 return sum |
We know that we cannot add if the current number is 13 or
the previous number was 13 (provided that there is a previous
number) -- so let's create a helper function to tell us, at any position
that we are at in the list, whether we can add the number or not.
And since this helper function is not likely to be useful for any purpose outside the sum13() function, let's hide it inside sum13(). |
Return the sum of the numbers in the array,
except ignore sections of numbers starting with a 6 and extending to the
next 7 (every 6 will be followed by at least one 7). Return 0 for no
numbers. sum67([1, 2, 2]) → 5 sum67([1, 2, 2, 6, 99, 99, 7]) → 5 sum67([1, 1, 6, 7, 2]) → 4 |
|
1. Keep track of whether we are
able to add or not...
def sum67(nums): YesWeCanAdd = True sum = 0 for n in nums: if n == 6: YesWeCanAdd = False elif YesWeCanAdd: sum += n elif not YesWeCanAdd and n == 7: YesWeCanAdd = True return sum |
The variable YesWeCanAdd tells us whether we're in a region of the list where we can add the numbers. We immediately make it False if we see a 6, and keep it False until we see the following 7. |
2. Remove the regions of the list
between 6 and 7
def sum67(nums): # remove the regions between 6 and 7 while 6 in nums: pos6 = nums.index(6) pos7 = nums[pos6:].index(7) + pos6 del nums[pos6:pos7+1] # add up every number that remains in the list return reduce(lambda x,y: x+y, nums, 0) |
We want to remove the regions of the list between a 6 and
the next 7.
We know that when we have removed all of those regions, there will be no 6s left in the list (though there may be 7s left over). So we find position of the first 6 in the list, and then the position of the first 7 after that (carefully), and remove that region -- note that we are guaranteed that there will be a 7 after a 6. We do this until there are no more 6s left. |
Given an array of ints, return True if the array
contains a 2 next to a 2 somewhere. has22([1, 2, 2]) → True has22([1, 2, 1, 2]) → False has22([2, 1, 2]) → False |
|
1. Keep track of whether we've just
seen a 2 a moment ago...
def has22(nums): JustSawA2 = False for n in nums: if JustSawA2 and n == 2: return True JustSawA2 = (n == 2) return False |
Note: the expression (n == 2) results in (returns) a True or False, which we just assign to JustSawA2, and we do this assignment just before going on to the next number. |
2. Convert the list into a string,
and do a string search...
def has22(nums): arr_of_strings = [str(n) for n in nums] str_with_separators = '-' + '-'.join(arr_of_strings) + '-' return '-2-2-' in str_with_separators |
Suppose we executed has22([2, 3, 22, 2, 1, 2]). The
correct answer would be False. Going through the code...
arr_of_string is ['2', '3', '22', '2', '1', '2'] str_with_separators is '-2-3-22-2-1-2-' '-2-2-' in str_with_separators is False |