On 11 November 2013 10:39, Chris Angelico <ros...@gmail.com> wrote: > On Mon, Nov 11, 2013 at 9:09 PM, <lorenzo.ga...@gmail.com> wrote: >> Regarding the "select" statement, I think the most "Pythonic" approach is >> using dictionaries rather than nested ifs. >> Supposing we want to decode abbreviated day names ("mon") to full names >> ("Monday"): > > You can't [normally], for instance, build up a > dictionary that handles inequalities, but you can do that with elif. > [...] Consider the following logic: > > A 'minor weapon' is based on a roll of a 100-sided dice. If it's 01 to > 70, "+1 weapon: 2,000gp [weapon]"; if it's 71 to 85, "+2 weapon: > 8,000gp [weapon]"; if 86 to 90, "Specific weapon [minor specific > weapon]"; and if 91 to 100, "Special ability [minor special weapon] > and roll again". > > My code to handle that starts out with this array: > > "minor weapon":({ > 70,"+1 weapon: 2,000gp [weapon]", > 85,"+2 weapon: 8,000gp [weapon]", > 90,"Specific weapon [minor specific weapon]", > 100,"Special ability [minor special weapon] and roll again", > }), > > (that's Pike; in Python it'd be a list, or maybe a tuple of tuples), > and denormalizes it into a lookup table by creating 70 entries quoting > the first string, 15 quoting the second, 5, and 10, respectively. So, > with a bit of preprocessing, a lookup table (which in this case is an > array (list), but could just as easily be a dict) can be used to > handle inequalities.
The obvious way to me is a binary search: from bisect import bisect_left class FloorMap: def __init__(self, dct): self.indexes = sorted(list(dct)) self.dct = dct def __getitem__(self, itm): index = self.indexes[bisect_left(self.indexes, itm)] return self.dct[index] minor_weapon = FloorMap({ 70: "+1 weapon: 2,000gp [weapon]", 85: "+2 weapon: 8,000gp [weapon]", 90: "Specific weapon [minor specific weapon]", 100: "Special ability [minor special weapon] and roll again" }) minor_weapon[63] #>>> '+1 weapon: 2,000gp [weapon]' The precise details of the wrapper class here are just to make initialisation pretty; it could be done straight from a pair of lists too: from bisect import bisect_left minor_weapon_indexes = 70, 85, 90, 100 minor_weapon_descriptions = ( "+1 weapon: 2,000gp [weapon]", "+2 weapon: 8,000gp [weapon]", "Specific weapon [minor specific weapon]", "Special ability [minor special weapon] and roll again" ) minor_weapon_descriptions[bisect_left(minor_weapon_indexes, 80)] #>>> '+2 weapon: 8,000gp [weapon]' Compare to if 80 <= 70: res = "+1 weapon: 2,000gp [weapon]" elif 80 <= 85: res = "+2 weapon: 8,000gp [weapon]" elif 80 <= 90: res = "Specific weapon [minor specific weapon]" elif 80 <= 100: res = "Special ability [minor special weapon] and roll again" which although shorter¹ is a lot less data-driven and much less reusable. ¹ Longer if you ignore the import and class declaration. -- https://mail.python.org/mailman/listinfo/python-list