check for dictionary keys

John Machin sjmachin at lexicon.net
Mon Jun 5 21:10:06 EDT 2006


On 5/06/2006 10:46 PM, Bruno Desthuilliers wrote:
> micklee74 at hotmail.com a écrit :
>> hi
>> in my code, i use dict(a) to make to "a" into a dictionary , "a" comes
>> from user input, so my program does not know in the first place. Then
>> say , it becomes
>>
>> a = { '-A' : 'value1' , '-B' : "value2" , "-C" : "value3" , '-D' :
>> 'value4' }
>>
>> somewhere next in my code, i will check for these..:
>>
>> 1)  -A and -B cannot exist together
>> 2) -A and -C cannot exist together
>> 3) -A and -B and -D cannot exist together
>> 4) and lots of other combinations to check for....
> 
> Looks like an option parser... If so, there's all you need in the 
> standard lib (look for the optparse module).
> 
>>
>> how can i efficiently check for the above? At first as i do simple
>> checks , i use if and else.
>> But as i began to check for more combinatoiuns, it gets messy....
> 
> First : use boolean logic (truth table, Kernaugh diagram, etc) to 
> simplify things. As an example, rule #3 is useless - it's a subset of 
> rule #1 (-A and -B and -D implies -A and -B). This should greatly reduce 
> the number of needed tests.

Good idea, but doesn't scale well. Simple code can weed out redundant 
rules, including any accidental duplicates that may creep into a long 
list. See code listing at end.

> 
> Then, write a simple rule system describing either valid inputs or 
> invalid inputs (preferably the smallest set !-). FWIW, it can be as 
> simple as a list of lambdas/error messages pairs, with lambdas being 
> predicate taking dict keys as params:
> 
> 
> _RULES = [
>   (lambda keys : '-A' in keys and '-B' in keys,
>    "can't have both options -A and -B"),
>   (lambda keys : '-A' in keys and '-C' in keys,
>    "can't have both options -A and -C"),
>   # etc...
> ]
> 

The evil HR director won't let the PHB pay me on a per LOC basis, so 
I've had to come up with a compact table-driven approach :-)

> def validate(options, rules):
>   keys = options.keys()
>   for predicate, message in rules:
>     if not predicate(keys):
>       raise ValueError(message)

Cheers,
John

C:\junk>type option_combos.py
bad_combos = ['ABD', 'AC', 'AB', 'CA']

def rule_compaction(bc_list, verbose=False):
     # The next few lines are admittedly oldfashioned :-)
     bc_sets = [set(x) for x in bc_list]
     deco = [(len(y), y) for y in bc_sets]
     deco.sort()
     bc_sets = [z[1] for z in deco]
     del deco
     if verbose:
         print "bc_sets #1:", bc_sets
     for k in xrange(len(bc_sets)-1, 0, -1):
         candidate = bc_sets[k]
         for ko in bc_sets[:k]:
             if ko <= candidate:
                 if verbose:
                     print candidate, "knocked out by", ko
                 del bc_sets[k]
                 break
     if verbose:
         print "bc_sets #2:", bc_sets
     return bc_sets

option_rules = rule_compaction(bad_combos, verbose=True)

def combo_disallowed_by(opt_set, rules):
     for rule in rules:
         if opt_set >= rule:
             return rule
     return None # redundantly, for emphasis

if __name__ == "__main__":
     import sys
     for opt_string in sys.argv[1:]:
         failer = combo_disallowed_by(set(opt_string), option_rules)
         if failer:
             print repr(opt_string), "disallowed by", failer
         else:
             print repr(opt_string), "is OK"

=== a test ===

C:\junk>option_combos.py A AB AC AD BC ABD ABX XBA BX
bc_sets #1: [set(['A', 'C']), set(['A', 'B']), set(['A', 'C']), 
set(['A', 'B', 'D'])]
set(['A', 'B', 'D']) knocked out by set(['A', 'B'])
set(['A', 'C']) knocked out by set(['A', 'C'])
bc_sets #2: [set(['A', 'C']), set(['A', 'B'])]
'A' is OK
'AB' disallowed by set(['A', 'B'])
'AC' disallowed by set(['A', 'C'])
'AD' is OK
'BC' is OK
'ABD' disallowed by set(['A', 'B'])
'ABX' disallowed by set(['A', 'B'])
'XBA' disallowed by set(['A', 'B'])
'BX' is OK

=== the end ===



More information about the Python-list mailing list