-1

Problem description

I want to used an object as a key in a dictionary. The attributes of the dictionary that I want to use to compare the keys are: DDATE, WEEK_PERIOD, DPERIOD, RPERIOD, ALLIANCE, DTIME, RTIME. I want exclude the attributes DCXR, RCXR, DCNX, RCNX.

The output of the algorithm should be:

AC, DL, SN, AF, LH

The problem is that as output it is only producing:

AC AF

The other values are totally lost. However When I add DCXR, RCXR, DCNX, RCNX to the hash and eq I get the right output. But I don't want THAT!! I don't want to use them when I insert keys in the dictionary.

I don't understand why it is excluding the other values in the output. From what I know I don't have to use all the attributed when I use the object as a Key in a dictionary.

The following source code produces exactly the error.


Source code

#!/usr/bin/env python
import os
import sys
import argparse

from collections import defaultdict

from functools import partial

class Key(object):
    def __init__(self, DDATE, WEEK_PERIOD, DPERIOD, RPERIOD, ALLIANCE, DTIME, RTIME, DCXR, RCXR, DCNX, RCNX):
            self.DDATE       = DDATE
            self.WEEK_PERIOD = WEEK_PERIOD
            self.DPERIOD     = DPERIOD
            self.RPERIOD     = RPERIOD
            self.ALLIANCE    = ALLIANCE
            self.DTIME = DTIME
            self.RTIME = RTIME
            self.DCXR = DCXR
            self.RCXR = RCXR
            self.DCNX = DCNX
            self.RCNX = RCNX
    
    def __hash__(self):
        return hash((self.DDATE, self.WEEK_PERIOD, self.DPERIOD, self.RPERIOD, self.ALLIANCE,
                     self.DTIME, self.RTIME))

    def __eq__(self, other):
        return (self.DDATE, self.WEEK_PERIOD, self.DPERIOD, self.RPERIOD, self.ALLIANCE, 
        self.DTIME, self.RTIME) == (other.DDATE, other.WEEK_PERIOD, other.DPERIOD, other.RPERIOD, other.ALLIANCE, other.DTIME, other.RTIME)

    def __ne__(self, other):
        return not(self == other)


if __name__ == "__main__":
    
    dict = defaultdict(partial(defaultdict, list)) 
    
    key = Key("01/15/17","2","1","2","0","13:50","18:25","AF","AF","CDG","YUL")
    dict[key][28].append(10.0)
        
    key = Key("01/15/17","2","1","2","0","13:05","20:10","AC","AC","CDG","YUL")
    dict[key][28].append(20.0)
        
    key = Key("01/15/17","2","1","2","0","13:50","18:25","DL","DL","CDG","YUL")
    dict[key][28].append(30.0)
        
    key = Key("01/15/17","2","1","2","0","13:05","20:10","SN","SN","CDG","YUL")
    dict[key][28].append(40.0)
        
    key = Key("01/15/17","2","1","2","0","13:05","20:10","LH","LH","CDG","YUL")
    dict[key][28].append(50.0)
    
    for key in dict.keys():
        print key.DCXR
Community
  • 1
  • 1
Hani Gotc
  • 840
  • 11
  • 24
  • I didn't, but it could be because they found your question unclear. I'm still trying to understand what you mean. Could you make your question clearer? – Thierry Lathuille Jul 12 '17 at 11:12
  • @ThierryLathuille I insert 5 keys in a dictionary. and I end up with 2 keys only. I don't understand why. The output should be **AC, DL, SN, AF, LH** but I only get **AC AF**. I really don't understand why?? I also used the data to reproduce the error – Hani Gotc Jul 12 '17 at 11:14

1 Answers1

1

Those objects don't vanish, they are just never inserted into the dict as keys. You say that you don't want to include DCXR, RCXR, DCNX, RCNX in the computation of the hash. That's fine. But you should include them in the __eq__ check. Otherwise objects that differ in those attributes only are considered equal. This is exactly the case for your example:

  • The 1st and 3rd only differ in those attributes.
  • The 2nd, 4th and 5th also only differ in those attributes.

So what happens is that the 1st and 2nd objects are inserted as keys and for each subsequent dict[key] the old value is just overwritten because the keys compare equal.


Side note: You shouldn't use dict as a variable name because it shadows the built-in type dict.

a_guest
  • 34,165
  • 12
  • 64
  • 118
  • A_guest thank you so much. can I show you this link pls https://stackoverflow.com/questions/4901815/object-of-custom-type-as-dictionary-key In the following link they don't use length in the equal. I followed what they did. This is what confused me – Hani Gotc Jul 12 '17 at 11:20
  • 1
    @HaniGotc You have correctly implemented the two methods `__hash__` and `__eq__` however both do not include the attributes `DCXR, RCXR, DCNX, RCNX`. Therefore `Key("01/15/17","2","1","2","0","13:50","18:25","AF","AF","CDG","YUL")` and `Key("01/15/17","2","1","2","0","13:50","18:25","DL","DL","CDG","YUL")` compare equal and are considered the very same key (which leads to an update of the associated value). A dictionary is basically a hash map with linked lists as target objects. It uses the `__eq__` check to determine whether a key is already part of the corresponding list. – a_guest Jul 12 '17 at 11:26
  • thank you @a_guest. I thought that something was wrong the program. you really helped. I understand – Hani Gotc Jul 12 '17 at 11:29