Vaibhav Aggarwal
Vaibhav Aggarwal

Reputation: 1411

python dictionary check if any key other than given keys exist

Lets say I have a dictionary that specifies some properties for a package:

d = {'from': 'Bob', 'to': 'Joe', 'item': 'book', 'weight': '3.5lbs'}

To check the validity of a package dictionary, it needs to have a 'from' and 'to' key, and any number of properties, but there must be at least one property. So a dictionary can have either 'item' or 'weight', both, but can't have neither. The property keys could be anything, not limited to 'item' or 'weight'.

How would I check dictionaries to make sure they're valid, as in having the 'to', 'from', and at least one other key?

The only method I can think of is by obtaining d.keys(), removing the 'from' and 'to' keys, and checking if its empty.

Is there a better way to go about doing this?

Upvotes: 5

Views: 5129

Answers (4)

Dylan Madisetti
Dylan Madisetti

Reputation: 775

This doesn't address the problem OP has, but provides what I think to be a better practice solution. I realize there's already been an answer but I just spent a few minutes reading on best practices and thought I would share

Problems with using a dictionary:

  • Dictionaries are meant to be on a key value basis. You inherently have 2 different types of key values given that to and from are mandatory while item and weight are optional
  • Dictionaries are meant to be logic-less. By setting certain requirements, you violate the principal of a dictionary which is just meant to hold data. To make a instance you need to build some sort of logic constructor for the dictionary

So why not just use a class? Proposed alternative:

class D(dict): # inheirits dict
   def __init__ (self,t,f,**attributes): # from is a keyword
       self['to'] = t
       self['from'] = f

       if(len(attributes) > 0):
           self.update(attributes)
       else:
           raise Exception("Require attribute")

d = D('jim','bob',item='book')
print d # {'to': 'jim', 'from': 'bob', 'item': 'book'}
print d['to'] # jim
print d['item'] # item
print d['from'] # bob

d = D('jim','bob') # throws error

Obviously this falls apart if to and from are set asynchronously but I think the base idea still holds. Creating a class also gives you the verbosity to prevent to and from from being overwritten/deleted as well as limiting the minimum/maximum of attributes set.

Upvotes: 1

thefourtheye
thefourtheye

Reputation: 239453

must = {"from", "to"}
print len(d) > len(must) and all(key in d for key in must)
# True

This solution makes sure that your dictionary has more elements than the elements in the must set and also all the elements in must will be there in the dictionary.

The advantage of this solution is that, it is easily extensible. If you want to make sure that one more parameter exists in the dictionary, just include that in the must dictionary, it will work fine. You don't have to alter the logic.

Edit

Apart from that, if you are using Python 2.7, you can do this more succinctly like this

print d.viewkeys() > {"from", "to"}

If you are using Python 3.x, you can simply write that as

print(d.keys() > {"from", "to"})

This hack works because, d.viewkeys and d.keys return set-like objects. So, we can use set comparison operators. > is used to check if the left hand side set is a strict superset of the right hand side set. So, in order to satisfy the condition, the left hand side set-like object should have both from and to, and some other object.

Quoting from the set.issuperset docs,

set > other

Test whether the set is a proper superset of other, that is, set >= other and set != other.

Upvotes: 12

A.J. Uppal
A.J. Uppal

Reputation: 19264

Use the following code:

def exists(var, dict):
    try:
        x = dict[var]
        return True
    except KeyError:
        return False

def check(dict):
    if exists('from', dict) == False:
        return False
    if exists('to', dict) == False:
        return False
    if exists('item', dict) == False and exists('weight', dict) == False:
        return False
    return True

def main():
    d = {'from': 'Bob', 'to': 'Joe', 'item': 'book', 'weight': '3.5lbs'}
    mybool = check(d)
    print mybool

if __name__ == '__main__':
    main()

Upvotes: 1

David
David

Reputation: 7456

if d.keys() has a length of at least 3, and it has a from and to attribute, you're golden.

My knowledge of Python isn't the greatest but I imagine it goes something like if len(d.keys) > 2 and d['from'] and d['to']

Upvotes: 1

Related Questions