| 1559 | # Hierarchical clustering is slow but the optimal solution guaranteed in O(len(vectors) ** 3). |
| 1560 | |
| 1561 | class Cluster(list): |
| 1562 | |
| 1563 | def __init__(self, *args, **kwargs): |
| 1564 | """ A nested list of Cluster and Vector objects, |
| 1565 | returned from hierarchical() clustering. |
| 1566 | """ |
| 1567 | list.__init__(self, *args, **kwargs) |
| 1568 | |
| 1569 | @property |
| 1570 | def depth(self): |
| 1571 | """ Yields the maximum depth of nested clusters. |
| 1572 | Cluster((1, Cluster((2, Cluster((3, 4)))))).depth => 2. |
| 1573 | """ |
| 1574 | return max([0] + [1 + n.depth for n in self if isinstance(n, Cluster)]) |
| 1575 | |
| 1576 | def flatten(self, depth=1000): |
| 1577 | """ Flattens nested clusters to a list, down to the given depth. |
| 1578 | Cluster((1, Cluster((2, Cluster((3, 4)))))).flatten(1) => [1, 2, Cluster(3, 4)]. |
| 1579 | """ |
| 1580 | a = [] |
| 1581 | for item in self: |
| 1582 | if isinstance(item, Cluster) and depth > 0: |
| 1583 | a.extend(item.flatten(depth-1)) |
| 1584 | else: |
| 1585 | a.append(item) |
| 1586 | return a |
| 1587 | |
| 1588 | def traverse(self, visit=lambda cluster: None): |
| 1589 | """ Calls the given visit() function on this cluster and each nested cluster, breadth-first. |
| 1590 | """ |
| 1591 | visit(self) |
| 1592 | for item in self: |
| 1593 | if isinstance(item, Cluster): |
| 1594 | item.traverse(visit) |
| 1595 | |
| 1596 | def __repr__(self): |
| 1597 | return "Cluster(%s)" % list.__repr__(self)[1:-1] |
| 1598 | |
| 1599 | def sequence(i=0, f=lambda i: i+1): |
| 1600 | """ Yields an infinite sequence, for example: |
no outgoing calls
no test coverage detected
searching dependent graphs…