aboutsummaryrefslogtreecommitdiffstats
path: root/tagit/utils/rmatcher.py
blob: b5bb8028b2d37816fbac35a9634ba896954ed662 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
"""

Part of the tagit module.
A copy of the license is provided with the project.
Author: Matthias Baumgartner, 2022
"""
# exports
__all__ = (
    'by_area',
    'by_area_min',
    )


## code ##

def by_area(target, candidates):
    """Pick the item from *candidates* whose area is most similar to *target*."""
    target_area = target[0] * target[1]
    scores = [
        (key, abs(target_area - res[0] * res[1]))
        for key, res in candidates
        ]
    best_key, best_score = min(scores, key=lambda key_score: key_score[1])
    return best_key


def by_area_min(target, candidates):
    """Pick the item from *candidates* whose area is at least that of *target*."""
    # rank the candidates by area difference
    # a positive score means that the candidate is larger than the target.
    target_area = target[0] * target[1]
    scores = [(key, res[0] * res[1] - target_area) for key, res in candidates]

    # identify the two items with
    # a) the smallest positive score (kmin), or
    # b) the largest negative score (kmax)
    kmin, kmax = None, None
    cmin, cmax = float('inf'), float('-inf')
    for key, score in scores:
        if score >= 0 and score < cmin:
            kmin, cmin = key, score
        elif score < 0 and score > cmax:
            kmax, cmax = key, score

    # prefer positive over negative scores
    if cmin < float('inf'):
        return kmin
    if cmax > float('-inf'):
        return kmax
    # no viable resolution found
    raise IndexError('list contains no valid element')

## EOF ##