(sorry, Peter, Alan, I sent two mails to you privately. I just switched from Yahoo to Hotmail for DMARC reasons. Still getting used to Hotmail.)
> Subject: RE: [Tutor] value range checker > Date: Fri, 28 Aug 2015 10:14:49 +0000 > > ---------------------------------------- >> To: [email protected] >> From: [email protected] >> Date: Thu, 27 Aug 2015 09:48:46 +0200 >> Subject: Re: [Tutor] value range checker >> >> Albert-Jan Roskam wrote: >> >>> 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. >> >>> My questions: >> >>> 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) >> >> >>> [1] @ is_valid: is there a better way to do this? I mostly don't like the >>> [use of the __iadd__ dunder method. >> >> When you find yourself using a list comprehension for its side effect it is >> high time to switch to a for loop. So >> >> def get_valid_value_lookup(records): >> boundaries = {} >> for category, minval, maxval in records: >> boundaries.setdefault(category, []).extend(range(minval, maxval+1)) >> return boundaries > > > ah, this indeed looks better. Thank you! > > >>> [2] @ is_valid2: Perhaps an answer to my previous question. Is this a >>> [better approach? >> >> As long as the size of the ranges is manageable and you are not actually >> seeing float values I'd stick with the dead simple first version. > > > The acronym "YAGNI" came to mind when I wrote that function. :-) But I was > just curious how it could be generalized an this was a first attempt. > > >> Replace the list in get_valid_value_lookup() with a set >> >> boundaries.setdefault(category, set()).update(range(minval, maxval+1)) >> >> and you get O(1) lookup for free. >> >>> 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 >> >> I don't understand what this is supposed to do: >> >> (1) for bisect to work correctly the list has to be sorted. Your >> get_valid_value_lookup() doesn't do that > > > awww, good point. The rows are currently sorted in the database, but it is > still a simple "just in case" thing to to sort the data. > > >> (2) Why/how are L[0], 0, and L[-1] special? > > > No idea actually. You've spotted the bug I *deliberately* added? :-)) > > >> (3) Given a sorted list L there should be no need to bisect_whatever for >> value < L[0] >> >> >>> [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. >> >> Unless you're encountering an actual inconvenience just keep it like it is. >> Yea, I'm a lazy bastard ;) > > > :-) I would like to store the validation and check functions in a central > location where they can easily be (re)used and maintained. > > For example, we also have to do a modulus-11 check, and I really am > relucatant to have multiple functions for the same check (e.g. > > one an SQL check constraint, one in Python, perhaps even one in JavaScript. > > > _______________________________________________ Tutor maillist - [email protected] To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
