4

I am trying to determine if a specific key and value pair exist in a dictionary; however, if I use the contains or has-key method, it only checks for the key. I need it to check both the key and the specific value. Some background: We have a total of 4 dictionaries: one for A, B, CompareList, and ChangeList. Once A is initialized, I put A's contents into CompareList (I would compare them directly; but A and B are double hash tables. And I've tried all of the methods here; but none of them work for me). So once we put A into CompareList, I compare it with the ObjectAttributes dictionary in B to see if anything changed. So for example, B may have the key,value pairs shape:circle and fill:no. If CompareList had shape:circle and fill:yes, then I want only fill:yes to be ChangeList. The problem lies in the "if attributes.getName() not in self.CompareList:" line. Here is the code; I am running it on Python 2.7.8. Thanks in advance for any help!!

class ObjectSemanticNetwork:
    def __init__(self):
        self.ObjectNames = {}
        self.ObjectAttributes = {}

    def setName(self, name):
        self.ObjectNames[name] = self.ObjectAttributes

    def setData(self, name, attribute):
        self.ObjectAttributes[name] = attribute

    def checkData(self, key):
        print(key)
        for key, value in self.ObjectAttributes.iteritems():
            print(key)
            print(value)
            print("\n")
class Agent:
(self):
        self.CompareList = {}
        self.ChangeListAB = {}
        self.ChangeListCD = {}

    def addToCompareList(self, name, value):
        self.CompareList[name] = value

    def addToChangeListAB(self, name, value):
        self.ChangeListAB[name] = value

    def addToChangeListCD(self, name, value):
        self.ChangeListCD[name] = value

    def CheckList(self, List, ListName):
        print '-------------------------',ListName,'--------------------------------'
        for key, value in List.iteritems():
            print(key)
            print(value)

    def Solve(self,problem):
        OSNAB = ObjectSemanticNetwork()
        for object in problem.getFigures().get("A").getObjects():
            for attributes in object.getAttributes():
                self.addToCompareList(attributes.getName(), attributes.getValue())
                OSNAB.ObjectNames["A"] = OSNAB.setData(attributes.getName(), attributes.getValue())
        #OSNAB.checkData("A")
        self.CheckList(self.CompareList,"CompareList")

        for object in problem.getFigures().get("B").getObjects():
            for attributes in object.getAttributes():
                if attributes.getName() not in self.CompareList:
                    self.addToChangeListAB(attributes.getName(), attributes.getValue())
                OSNAB.ObjectNames["B"] = OSNAB.setData(attributes.getName(), attributes.getValue())
        # OSNAB.checkData("B")
        self.CheckList(self.ChangeListAB,"ChangeList")

        OSNCD = ObjectSemanticNetwork()
        for object in problem.getFigures().get("C").getObjects():
            for attributes in object.getAttributes():
                OSNCD.ObjectNames["C"] = OSNCD.setData(attributes.getName(), attributes.getValue())
        # OSNCD.checkData("C")

        for object in problem.getFigures().get("1").getObjects():
            for attributes in object.getAttributes():
                OSNCD.ObjectNames["D"] = OSNCD.setData(attributes.getName(), attributes.getValue())
        # OSNCD.checkData("D")

        return "6"
enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
Elijah Philpotts
  • 55
  • 1
  • 1
  • 8
  • 3
    what's wrong with `key in dictionary and dictionary[key] == value`? – Aprillion Sep 07 '14 at 15:14
  • The problem with this way (and I should have specified this earlier) is that because I am doing A LOT of iterations, using an "and" in the if statement would add time. We have to optimize as much as possible; so any additional overhead to an already complicated problem is bad. Thanks for helping. – Elijah Philpotts Sep 07 '14 at 15:37
  • really? creating new try/except stacks (as in accepted answer) is faster in your case than a simple little `and` operator? I guess the keys almost always already exist in your case or perhaps compilers can optimize it better.. what is the timing difference from your profiling plz - is the improvement in order of magnitudes? – Aprillion Sep 07 '14 at 15:55
  • @ElijahPhilpotts: When in doubt, profile. Both `key in dictionary` and `dictionary[key] == value` are implemented in C. The additional cost of try-except in a Python level function should make `checkKeyValuePairExistence` less efficient. – Steven Rumbalski Sep 07 '14 at 15:58
  • @ElijahPhilpotts: I added some timings to my answer. Check it out. – Steven Rumbalski Sep 07 '14 at 16:25
  • I ended up taking out the function; you were right. I was always told that scripting languages were much slower than C++; so I wasn't sure how true this was. Thanks for your help. – Elijah Philpotts Sep 08 '14 at 18:56

3 Answers3

11

Use

if key in d and d[key] == value:

Or (only in Python 3)

if (key, value) in d.items():

In Python 3 d.items() returns a Dictionary view object, which supports fast membership testing. In Python 2 d.items() returns a list, which is both slow to create and slow to to test membership. Python 2.7 is a special case where you can use d.viewitems() and get the same thing that you get with d.items() in Python 3.

Edit: In a comment you indicate that for performance reasons you prefer checkKeyValuePairExistence over key in d and d[key] == value. Below are some timings showing that checkKeyValuePairExistence is always slower (by about 2x on my system when the key-value pair is present 16x when it is not). I also tested larger and smaller dictionaries and found little variation in the timings.

>>> import random
>>> from timeit import timeit
>>> def checkKeyValuePairExistence(dic, key, value):
...     try:
...         return dic[key] == value
...     except KeyError:
...         return False
...
>>> d = {random.randint(0, 100000):random.randint(0, 100000) for i in range(1000)}
>>> setup = 'from __main__ import k, d, v, checkKeyValuePairExistence'
>>> test_try_except = 'checkKeyValuePairExistence(d, k, v)'
>>> test_k_in_d_and = 'k in d and d[k] == v'
>>> k, v = random.choice(d.items()) # to test if found
>>> timeit(test_try_except, setup=setup)
0.1984054392365806
>>> timeit(test_k_in_d_and, setup=setup)
0.10442071140778353
>>> k = -1 # test if not found
>>> timeit(test_try_except, setup=setup)
1.2896073903002616
>>> timeit(test_k_in_d_and, setup=setup)
0.07827843747497809 
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
  • it might be noteworthy that the `not value` as 2nd argument of `get` is there to make non-existing key not equal to `None` (any other reason?) – Aprillion Sep 07 '14 at 15:20
  • @Aprillion: Correct. If the key was not in the dictionary and the value tested for was `None`, `d.get(key) == value` would incorrectly evaluate to `True`. – Steven Rumbalski Sep 07 '14 at 15:22
  • incorrectly, but sometimes it might be useful - in which case it's better written explicitly as `if value == None and key not in d ...` to prevent future headaches :) – Aprillion Sep 07 '14 at 15:24
  • Thanks for the help. I ended up using something similar to the second method. – Elijah Philpotts Sep 07 '14 at 15:38
  • @ElijahPhilpotts: `if key in d and d[key] == value` is such basic idiomatic Python that it doesn't need to be encapsulated in a function named `checkKeyValuePairExistence`. (But of course it is a matter of taste.) – Steven Rumbalski Sep 07 '14 at 15:47
2

How about this function:

def checkKeyValuePairExistence(dic, key, value):
    try:
        return dic[key] == value
    except KeyError:
        return False

If you are using another type of dictionary other then the one python offers (I'm sorry, I couldnt understand from your post if you are using it or not) then let me know and i'll try to give your another solution

Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
tomer.z
  • 1,033
  • 1
  • 10
  • 25
-1

Why not just do this:

a = {1:'a', 2:'b'}
b = (1, 'a')
print b in a.iteritems() # prints True
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
Chrispresso
  • 3,660
  • 2
  • 19
  • 31
  • -1. This negates one of the major advantages of dictionaries -- efficient membership testing. When the key-value pair is present the average search would need to visit half the items. It would need to search all the items to determine the key-value pair is not found. – Steven Rumbalski Sep 07 '14 at 15:42
  • A try-except example was already provided. I'm just adding a different example – Chrispresso Sep 07 '14 at 15:48
  • It's not really "just another example". I believe it is bad answer. Others can disagree and upvote. (Also, I edited a space into your answer because I accidentally upvoted it instead of downvoted it. I couldn't change my vote unless it was edited.) – Steven Rumbalski Sep 07 '14 at 15:52
  • Hey, it does what OP asked – Chrispresso Sep 07 '14 at 16:10