逆FizzBuzz問題

最近ぞっぷりと linq に染まっていたので、関数の入れ子をより気持ち悪く感じて困る. python にも組み込み linq を誰か.

from itertools import count, cycle, islice, ifilter

def FizzBuzz():
    seq = [None, None, "Fizz", None, "Buzz", "Fizz", None, None, "Fizz", "Buzz", None, "Fizz", None, None, "FizzBuzz"]
    for i, e in enumerate(cycle(seq)):
        if e == None:
            yield i + 1
        else:
            yield e

def skip(itrerable, count):
    return islice(itrerable, count, None)

def take(itrerable, count):
    return islice(itrerable, count)

def InverseFizzBuzz(seq):
    def work(start, count):
        i = start
        c = count
        a = []
        for x in skip(FizzBuzz(), start - 1):
            if c == 0:
                l = i - start
                return (a, l, range(start, start + l))
            if not isinstance(x, int):
                a += [x]
                c -= 1
            i += 1
    start_list = { "Fizz": [3, 6, 9, 12], "Buzz": [5, 10], "FizzBuzz": [15] }
    if len(seq) == 0:
        return None
    if not (seq[0] in start_list):
        return None
    candidates = list(ifilter(lambda x: x[0] == seq, [work(i, len(seq)) for i in start_list[seq[0]]]))
    if len(candidates) == 0:
        return None
    else:
        return list(sorted(candidates, cmp = lambda x, y: x[1] - y[1]))[0][2]

assert InverseFizzBuzz(["Fizz"]) == range(3, 4)
assert InverseFizzBuzz(["Buzz"]) == range(5, 6)
assert InverseFizzBuzz(["Fizz", "Buzz"]) == range(9, 11)
assert InverseFizzBuzz(["Buzz", "Fizz"]) == range(5, 7)
assert InverseFizzBuzz(["Fizz", "Buzz", "Fizz"]) == range(3, 7)
assert InverseFizzBuzz(["Buzz", "Fizz", "Buzz"]) == None
assert InverseFizzBuzz(["Fizz", "Fizz"]) == range(6, 10)
assert InverseFizzBuzz(["Fizz", "Fizz", "Buzz"]) == range(6, 11)

追記: 無駄があった・・・

def InverseFizzBuzz(seq):
    def work(start, count):
        i = start
        c = count
        a = []
        for x in skip(FizzBuzz(), start - 1):
            if c == 0:
                l = i - start
                return (a, l, range(start, start + l))
            if not isinstance(x, int):
                a += [x]
                c -= 1
            i += 1
    candidates = list(ifilter(lambda x: x[0] == seq, [work(i, len(seq)) for i in [3, 5, 6, 9, 10, 12, 15]]))
    if len(candidates) == 0:
        return None
    else:
        return list(sorted(candidates, cmp = lambda x, y: x[1] - y[1]))[0][2]