Functional Python Programming

(Wang) #1
Chapter 7

yield from rank_data(tuple(seq_or_iter), key)


data = seq_or_iter


head= seq_or_iter[0]


Convert to Rank_Data and process.


if not isinstance(head, Rank_Data):


ranked= tuple(Rank_Data((),d) for d in data)


for r, rd in rerank(ranked, key):


yield Rank_Data(rd.rank_seq+(r,), rd.raw)


return


Collection of Rank_Data is what we prefer.


for r, rd in rerank(data, key):


yield Rank_Data(rd.rank_seq+(r,), rd.raw)


We've decomposed the ranking into three cases for three different types of data.
We're forced it to do this when the different kinds of data aren't polymorphic
subclasses of a common superclass. The following are the three cases:



  • Given an iterable (without a usable getitem() method), we'll
    materialize a tuple that we can work with

  • Given a collection of some unknown type of data, we'll wrap the unknown
    objects into Rank_Data tuples

  • Finally, given a collection of Rank_Data tuples, we'll add yet another ranking
    to the tuple of ranks inside the each Rank_Data container


This relies on a rerank() function that inserts and returns another ranking into
the Rank_Data tuple. This will build up a collection of individual rankings from
a complex record of raw data values. The rerank() function follows a slightly
different design than the example of the rank() function shown previously.


This version of the algorithm uses sorting instead of creating a groups in a objects
like Counter object:


def rerank(rank_data_collection, key):


sorted_iter= iter(sorted( rank_data_collection, key=lambda
obj: key(obj.raw)))


head = next(sorted_iter)


yield from ranker(sorted_iter, 0, [head], key)


We've started by reassembling a single, sortable collection from the head and the
data iterator. In the context in which this is used, we can argue that this is a bad idea.

Free download pdf