Write generator functions below (each one is worth 4 points) that satisfy the following specifications. You may not import any of the generators in itertools or any other modules to write your generators. You may use any of the standard functions like zip and enumerate.
a. The sequence generator takes any number of iterables as parameters: it produces every value from the first iterable, followed by every value from the second iterable, etc.,. Hint: I used only for loops. For example for i in sequence('abc', 'd', 'ef', 'ghi'): print(i,end='') prints abcdefghi: all characters from 'abc', followed by all in 'd', followed by all in 'ef' etc..
b. The group_when generator takes one iterable and one predicate as parameters: it produces lists that each end in a value from the iterable where the predicate is True. If the iterable ends on a value for which the predicate returns False, yield a final list containing all the values from the one after the previous end to the last value produced by the iterable. Hint: I used a for loop . For example for i in group_when('combustibles', lambda x : x in 'aeiou'): print(i,end='') prints the 5 lists ['c', 'o']['m', 'b', 'u']['s', 't', 'i']['b', 'l', 'e']['s'].
c. The drop_last generator takes one iterable and one int as a parameter (call it n): it produces every value from the iterable except for the last n values (without being able to count how many values the iterable produces) Hint: I used an explicit call to iter and a while loop and a comprehension that creates a list that stores at most n values (so that data structure is allowed here). For example for i in drop_last('combustible', 5): print(i,end='') prints combus; if the iterable produces < n values, it terminates immediately, on the first call to next.
d. The yield_and_skip generator takes one iterable and one function (which takes one argument and returns an int) as parameters: it produces a value from the iterable but then it then skips the number of values specified when the function argument is called on the just-produced value. Hint: I used an explicit call to iter and a while and for loop. For example for i in yield_and_skip('abbabxcabbcaccabb',lambda x : {'a':1,'b':2,'c':3}.get(x,0)): print(i,end='') prints abxccab; prints a then skips 1; prints b then skips 2; prints x then skips 0; prints c then skips 3; …
e. The alternate_all generator takes any number of iterables as parameters: it produces the first value from the first parameter, then the first value from the second parameter, ..., then the first value from the last parameter; then the second value from the first parameter, then the second value from the second parameter, ..., then the second value from the last parameter; etc. If any iterable produces no more values, it is ignored. Eventually, this generator produces every value in each iterable. Hint: I used explicit calls to iter, and a while and for loop, and a try/except statement; you can create a list whose length is the same as the number of parameters (I stored iter called on each parameter in such a list). For example for i in alternate_all('abcde','fg','hijk'): print(i,end='') prints afhbgicjdke.