I have a real-world problem involving finding the best known term from a string containing sets of terms. We have Term
objects that are comparable in that they have a method a_term.is_better_than(other_term)
. This method is Boolean -- if it returns False
, then a_term
may be as good as other_term
, but isn't better.
Using this method, I need to pare down a set of terms to the best ones. The best way I've been able to think about this is to compare pairs of terms and eliminate any terms when one isn't as good as the other, something like this:
def get_best_terms(terms: Set[Term]): Set[Term]
best_terms = set()
m_terms = list(terms)
while m_terms:
term = m_terms.pop()
for i in reversed(range(len(m_terms))):
if term.is_better_than(m_terms[i]):
del m_terms[i]
if m_terms[i].is_better_than(term):
break
else: # We never encountered the `break` statement
best_terms.add(term)
break
best_terms |= {a_term for a_term in m_terms
if not (term.is_better_than(a_term) or
a_term.is_better_than(term))}
return best_terms
This approach is functional, but pretty gross in my opinion. For one thing, there's a lot of mutation going on here. For another, once I've identified a single best term, finding all the terms that are equally good is messy. The whole thing is hard to read.
What do you suggest?
Examples
A Term is a string with some metadata attached. For example,
a = AutoTerm(term='honda', term_span=1, term_range=(1, 2),
original_term='CAR HONDA ACC...')
b = AutoTerm(term='2015 honda accord', term_span=2, term_range=(1, 3),
original_term='2015 HONDA ACC...')
c = AutoTerm(term='2015 accord', ...)
Sometimes a term is a better choice because it's more specific, but there are other nuances, such as a match in a database. Let's say, arbitrarily, that b and c are equally good, but a
is not as good. Then
assert get_best_terms({a, b, c}) == {b, c}
should pass.
Term
and some example IO? \$\endgroup\$