Albert-Jan Roskam
2015-08-26 13:19:16 UTC
Hello,
I have a written a function checks the validity of values. The ranges of valid values are stored in a database table.
Such a table contains three columns: category, min and max. One record of such a table specifies the range for
a certain category, but a category may be spread out over multiple records.
For example, the category-min-max tuples
("cat a", 1, 1),
("cat a", 3, 3),
("cat a", 6, 10),
correspond to a range of category A of 1-1, 3-3, 6-10, which is the same as 1, and 3, and 6, 7, 8, 9, 10.
The code below does exactly what I want:
import collections
import bisect
import math
import pprint
def get_valid_value_lookup(records):
"""
Translates value range information (from a database table)
into a dictionary of the form {<category>: [<range of accepted values>]}
"""
Boundaries = collections.namedtuple("Boundaries", "category min max")
records = [Boundaries(*record) for record in records]
boundaries = collections.defaultdict(list)
crap = [boundaries[record.category].__iadd__(range(record.min, record.max + 1))
for record in records]
return dict(boundaries)
def is_valid(lookup, category, value):
"""Return True if value is member of a list of a given category, False otherwise."""
try:
return value in lookup[category]
except KeyError:
raise KeyError("Invalid category: %r" % category)
def is_valid2(lookup, category, value):
"""Return True if value is member of a list of a given category, False otherwise."""
# this version also knows how to deal with floats.
try:
L = lookup[category]
except KeyError:
raise KeyError("Invalid category: %r" % category)
adjusted_value = value if int(value) in (L[0], 0, L[-1]) else math.ceil(value)
try:
chopfunc = bisect.bisect_right if value < L[0] else bisect.bisect_left
return L[chopfunc(L, value)] == adjusted_value
except IndexError:
return False
if __name__ == '__main__':
L = [("cat a", 1, 1), ("cat a", 3, 3), ("cat a", 6, 10),
("cat b", 1, 9), ("cat c", 1, 2), ("cat c", 5, 9)]
lookup = get_valid_value_lookup(L)
assert not is_valid(lookup, "cat a", 999) # value 999 is invalid for category 1
assert is_valid(lookup, "cat a", 10)
assert not is_valid2(lookup, "cat a", 0.1)
assert not is_valid2(lookup, "cat a", -1)
assert is_valid2(lookup, "cat a", 6.1)
L2 = [(1, -5, 1), (1, 3, 3), (1, 6, 10), (2, 1, 9), (3, 1, 2), (3, 5, 9)]
lookup = get_valid_value_lookup(L2)
assert is_valid2(lookup, 1, -4.99)
assert is_valid2(lookup, 1, -5)
My questions:
[1] @ is_valid: is there a better way to do this? I mostly don't like the use of the __iadd__ dunder method.
[2] @ is_valid2: Perhaps an answer to my previous question. Is this a better approach?
[3] I am inheriting a this system. It feels a bit strange that these range check values are stored in a database.
Would yaml be a better choice? Some of the tables are close to 200 records.
Thank you in advance!
Albert-Jan
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
I have a written a function checks the validity of values. The ranges of valid values are stored in a database table.
Such a table contains three columns: category, min and max. One record of such a table specifies the range for
a certain category, but a category may be spread out over multiple records.
For example, the category-min-max tuples
("cat a", 1, 1),
("cat a", 3, 3),
("cat a", 6, 10),
correspond to a range of category A of 1-1, 3-3, 6-10, which is the same as 1, and 3, and 6, 7, 8, 9, 10.
The code below does exactly what I want:
import collections
import bisect
import math
import pprint
def get_valid_value_lookup(records):
"""
Translates value range information (from a database table)
into a dictionary of the form {<category>: [<range of accepted values>]}
"""
Boundaries = collections.namedtuple("Boundaries", "category min max")
records = [Boundaries(*record) for record in records]
boundaries = collections.defaultdict(list)
crap = [boundaries[record.category].__iadd__(range(record.min, record.max + 1))
for record in records]
return dict(boundaries)
def is_valid(lookup, category, value):
"""Return True if value is member of a list of a given category, False otherwise."""
try:
return value in lookup[category]
except KeyError:
raise KeyError("Invalid category: %r" % category)
def is_valid2(lookup, category, value):
"""Return True if value is member of a list of a given category, False otherwise."""
# this version also knows how to deal with floats.
try:
L = lookup[category]
except KeyError:
raise KeyError("Invalid category: %r" % category)
adjusted_value = value if int(value) in (L[0], 0, L[-1]) else math.ceil(value)
try:
chopfunc = bisect.bisect_right if value < L[0] else bisect.bisect_left
return L[chopfunc(L, value)] == adjusted_value
except IndexError:
return False
if __name__ == '__main__':
L = [("cat a", 1, 1), ("cat a", 3, 3), ("cat a", 6, 10),
("cat b", 1, 9), ("cat c", 1, 2), ("cat c", 5, 9)]
lookup = get_valid_value_lookup(L)
assert not is_valid(lookup, "cat a", 999) # value 999 is invalid for category 1
assert is_valid(lookup, "cat a", 10)
assert not is_valid2(lookup, "cat a", 0.1)
assert not is_valid2(lookup, "cat a", -1)
assert is_valid2(lookup, "cat a", 6.1)
L2 = [(1, -5, 1), (1, 3, 3), (1, 6, 10), (2, 1, 9), (3, 1, 2), (3, 5, 9)]
lookup = get_valid_value_lookup(L2)
assert is_valid2(lookup, 1, -4.99)
assert is_valid2(lookup, 1, -5)
My questions:
[1] @ is_valid: is there a better way to do this? I mostly don't like the use of the __iadd__ dunder method.
[2] @ is_valid2: Perhaps an answer to my previous question. Is this a better approach?
[3] I am inheriting a this system. It feels a bit strange that these range check values are stored in a database.
Would yaml be a better choice? Some of the tables are close to 200 records.
Thank you in advance!
Albert-Jan
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor