Skip to content

Commit f528b8b

Browse files
committed
"fullyflatten" does not need to be a class method.
This won't improve performance, but it gives easier access to that function to work on it.
1 parent be3d65f commit f528b8b

File tree

3 files changed

+48
-76
lines changed

3 files changed

+48
-76
lines changed

cluster/cluster.py

Lines changed: 20 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
from __future__ import print_function
1919

20+
from .util import fullyflatten
21+
2022

2123
class Cluster(object):
2224
"""
@@ -27,7 +29,7 @@ class Cluster(object):
2729
"""
2830

2931
def __repr__(self):
30-
return "<Cluster@%s(%s)>" % (self.__level, self.__items)
32+
return "<Cluster@%s(%s)>" % (self.level, self.items)
3133

3234
def __str__(self):
3335
return self.__str__()
@@ -44,67 +46,18 @@ def __init__(self, level, *args):
4446
will get added as item to the cluster. You could also pass a list as
4547
second parameter to initialise the cluster with that list as content
4648
"""
47-
self.__level = level
49+
self.level = level
4850
if len(args) == 0:
49-
self.__items = []
50-
else:
51-
self.__items = list(args)
52-
53-
def append(self, item):
54-
"""
55-
Appends a new item to the cluster
56-
57-
:param item: The item that is to be appended.
58-
"""
59-
self.__items.append(item)
60-
61-
def items(self, new_items=None):
62-
"""
63-
Sets or gets the items of the cluster
64-
65-
:param new_items: if set, the items of the cluster will be replaced with
66-
that argument.
67-
"""
68-
if new_items is None:
69-
return self.__items
51+
self.items = []
7052
else:
71-
self.__items = new_items
72-
73-
def fullyflatten(self, *args):
74-
"""
75-
Completely flattens out this cluster and returns a one-dimensional
76-
list containing the cluster's items. This is useful in cases where
77-
some items of the cluster are clusters in their own right and you only
78-
want the items.
79-
80-
:param *args: only used for recursion.
81-
"""
82-
flattened_items = []
83-
if len(args) == 0:
84-
collection = self.__items
85-
else:
86-
collection = args[0].items()
87-
88-
for item in collection:
89-
if isinstance(item, Cluster):
90-
flattened_items = flattened_items + self.fullyflatten(item)
91-
else:
92-
flattened_items.append(item)
93-
94-
return flattened_items
95-
96-
def level(self):
97-
"""
98-
Returns the level associated with this cluster.
99-
"""
100-
return self.__level
53+
self.items = args
10154

10255
def display(self, depth=0):
10356
"""
10457
Pretty-prints this cluster. Useful for debuging.
10558
"""
106-
print(depth * " " + "[level %s]" % self.__level)
107-
for item in self.__items:
59+
print(depth * " " + "[level %s]" % self.level)
60+
for item in self.items:
10861
if isinstance(item, Cluster):
10962
item.display(depth + 1)
11063
else:
@@ -132,8 +85,8 @@ def topology(self):
13285
('.idlerc', '.pylint.d')))))))
13386
"""
13487

135-
left = self.__items[0]
136-
right = self.__items[1]
88+
left = self.items[0]
89+
right = self.items[1]
13790

13891
if isinstance(left, Cluster):
13992
first = left.topology()
@@ -166,27 +119,27 @@ def getlevel(self, threshold):
166119
useful approach.
167120
"""
168121

169-
left = self.__items[0]
170-
right = self.__items[1]
122+
left = self.items[0]
123+
right = self.items[1]
171124

172125
# if this object itself is below the threshold value we only need to
173126
# return it's contents as a list
174-
if self.level() <= threshold:
175-
return [self.fullyflatten()]
127+
if self.level <= threshold:
128+
return [fullyflatten(self.items)]
176129

177130
# if this cluster's level is higher than the threshold we will
178131
# investgate it's left and right part. Their level could be below the
179132
# threshold
180-
if isinstance(left, Cluster) and left.level() <= threshold:
133+
if isinstance(left, Cluster) and left.level <= threshold:
181134
if isinstance(right, Cluster):
182-
return [left.fullyflatten()] + right.getlevel(threshold)
135+
return [fullyflatten(left.items)] + right.getlevel(threshold)
183136
else:
184-
return [left.fullyflatten()] + [[right]]
185-
elif isinstance(right, Cluster) and right.level() <= threshold:
137+
return [fullyflatten(left.items)] + [[right]]
138+
elif isinstance(right, Cluster) and right.level <= threshold:
186139
if isinstance(left, Cluster):
187-
return left.getlevel(threshold) + [right.fullyflatten()]
140+
return left.getlevel(threshold) + [fullyflatten(right.items)]
188141
else:
189-
return [[left]] + [right.fullyflatten()]
142+
return [[left]] + [fullyflatten(right.items)]
190143

191144
# Alright. We covered the cases where one of the clusters was below
192145
# the threshold value. Now we'll deal with the clusters that are above

cluster/method/hierarchical.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from cluster.cluster import Cluster
2121
from cluster.matrix import Matrix
2222
from cluster.method.base import BaseClusterMethod
23-
from cluster.util import median, mean
23+
from cluster.util import median, mean, fullyflatten
2424

2525

2626
logger = logging.getLogger(__name__)
@@ -98,13 +98,13 @@ def uclus_distance(self, x, y):
9898
if not isinstance(x, Cluster):
9999
x = [x]
100100
else:
101-
x = x.fullyflatten()
101+
x = fullyflatten(x.items)
102102

103103
# create a flat list of all the items in <y>
104104
if not isinstance(y, Cluster):
105105
y = [y]
106106
else:
107-
y = y.fullyflatten()
107+
y = fullyflatten(y.items)
108108

109109
distances = []
110110
for k in x:
@@ -125,13 +125,13 @@ def average_linkage_distance(self, x, y):
125125
if not isinstance(x, Cluster):
126126
x = [x]
127127
else:
128-
x = x.fullyflatten()
128+
x = fullyflatten(x.items)
129129

130130
# create a flat list of all the items in <y>
131131
if not isinstance(y, Cluster):
132132
y = [y]
133133
else:
134-
y = y.fullyflatten()
134+
y = fullyflatten(y.items)
135135

136136
distances = []
137137
for k in x:
@@ -153,13 +153,13 @@ def complete_linkage_distance(self, x, y):
153153
if not isinstance(x, Cluster):
154154
x = [x]
155155
else:
156-
x = x.fullyflatten()
156+
x = fullyflatten(x.items)
157157

158158
# create a flat list of all the items in <y>
159159
if not isinstance(y, Cluster):
160160
y = [y]
161161
else:
162-
y = y.fullyflatten()
162+
y = fullyflatten(y.items)
163163

164164
# retrieve the minimum distance (single-linkage)
165165
maxdist = self.distance(x[0], y[0])
@@ -183,13 +183,13 @@ def single_linkage_distance(self, x, y):
183183
if not isinstance(x, Cluster):
184184
x = [x]
185185
else:
186-
x = x.fullyflatten()
186+
x = fullyflatten(x.items)
187187

188188
# create a flat list of all the items in <y>
189189
if not isinstance(y, Cluster):
190190
y = [y]
191191
else:
192-
y = y.fullyflatten()
192+
y = fullyflatten(y.items)
193193

194194
# retrieve the minimum distance (single-linkage)
195195
mindist = self.distance(x[0], y[0])

cluster/util.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ def flatten(L):
4444
return flatten(L[0]) + flatten(L[1:])
4545

4646

47+
def fullyflatten(container):
48+
"""
49+
Completely flattens out a cluster and returns a one-dimensional set
50+
containing the cluster's items. This is useful in cases where some items of
51+
the cluster are clusters in their own right and you only want the items.
52+
53+
:param container: the container to flatten.
54+
"""
55+
flattened_items = []
56+
57+
for item in container:
58+
if hasattr(item, 'items'):
59+
flattened_items = flattened_items + fullyflatten(item.items)
60+
else:
61+
flattened_items.append(item)
62+
63+
return flattened_items
64+
65+
4766
def median(numbers):
4867
"""
4968
Return the median of the list of numbers.

0 commit comments

Comments
 (0)