2012-08-28 5 views
2

Je travaille avec deux ensembles de données hiérarchiques qui contiennent une relation complexe (je n'utilise pas SQL) et ils ne partagent pas leur primaire clés de recherche. Nous utilisons ce processus pour garder les deux ensembles de données synchronisés.Python: J'ai une liste double clé, qui est l'objet de stockage le plus efficace pour retreival

Chaque jeu de données est actuellement stocké en tant que dictionnaire avec la clé de l'ensemble de données en tant que clé du dictionnaire. Une fois la relation complexe déterminée, je stocke la clé de l'autre ensemble de données en tant qu'attribut dans l'autre. Cela a créé le besoin de créer des fonctions auxiliaires étranges pour ensuite suivre certaines des relations parent-enfant. Je me demandais s'il y aurait une méthode plus efficace ou plus rapide pour cette folie puisque je dois actuellement passer les deux ensembles de données aux fonctions de traitement qui ont besoin d'analyser les relations.

exemples:

leftdataset = {'10000': { 'key': '10000', 'fkey':'asdf', 'parent':'10001'}, 
       '10001': { 'key': '10001', 'fkey':'qwer', 'parent':''},} 
rightdataset= {'asdf': { 'key': 'asdf', 'fkey':'10000', 'parent':'qwer'}, 
       'qwer': { 'key': 'qwer', 'fkey':'10001', 'parent':''}, 

Pour trouver ce parent fkey je dois: Je jouais

fkey = dataset[dataset['10000']['parent']]['fkey'] 

avec l'idée de présenter un tuple des paires de clés, puis la recherche de la clé dont j'ai besoin dans ce comme:

keys = [('10000', 'asdf'), ('10001', 'qwer')] 

def find_key(key, keyset): 
    for keypair in keys: 
    if key in keypair: 
     k1, k2 = keypair 
     if k1 == key: 
     return k2 
     else: 
     return k1 

Mais cela semble encore moins EF ficient que ce que je fais maintenant. Suis-je juste en train de me frayer un chemin?

+2

recherche aléatoire dans un dictionnaire sera beaucoup plus efficace que recherche aléatoire dans une liste , sauf si vous pouvez organiser les choses par un index. Je voudrais juste encapsuler les deux ensembles de données dans une classe et cacher le désordre là. –

Répondre

1

Est-ce l'utilisation appel à vous?

consultation facile et l'utilisation des entrées simples:

>>> left("10000") 
Entry({'parent': '10001', 'key': '10000', 'fkey': 'asdf'}) 
>>> left("10000")['key'] 
'10000' 
>>> left("10000")['parent'] 
'10001' 

consultation facile des parents:

>>> left("10000").parent() 
Entry({'parent': '', 'key': '10001', 'fkey': 'qwer'}) 
>>> left("10000").parent().parent() 
>>> left("10001") 
Entry({'parent': '', 'key': '10001', 'fkey': 'qwer'}) 
>>> left("10001") is left("10000").parent() 
True 

facile consultation des entrées connexes:

>>> left("10001").related() 
Entry({'parent': '', 'key': 'qwer', 'fkey': '10001'}) 
>>> right("qwer") 
Entry({'parent': '', 'key': 'qwer', 'fkey': '10001'}) 
>>> right(left("10001").related()['key']) 
Entry({'parent': '', 'key': 'qwer', 'fkey': '10001'}) 
>>> right("qwer") is left("10001").related() 
True 

Particulièrement voici l'exemple dans votre question: la clé étrangère du parent:

>>> left("10000").parent()['fkey'] 
'qwer' 

Si oui, alors voici le code! Classes:

class Entry(object): 
    def __init__(self, dataset, d): 
     self.dataset = dataset 
     self.d = d 

    def parent(self): 
     return self.dataset.parent_of(self) 
    def related(self): 
     if not self.dataset.related_dataset: 
      raise ValueError("no related dataset specified") 
     return self.dataset.related_dataset(self['fkey']) 

    def __getitem__(self, k): 
     return self.d.__getitem__(k) 

    def __repr__(self): 
     return "Entry(%s)" % repr(self.d) 
    def __str__(self): 
     return str(self.d) 

class Dataset(object): 
    def __init__(self, data): 
     self.data = dict((k, Entry(self, v)) for (k,v) in data.items()) 
     self.related_dataset = None 

    def set_related_dataset(self, dataset): 
     self.related_dataset = dataset 

    def entry(self, key): 
     if isinstance(key, Entry): return key 
     return self.data[key] 
    def __call__(self, key): 
     return self.entry(key) 

    def parent_of(self, entry): 
     entry = self.entry(entry) 

     if not entry['parent']: 
      return None 
     return self.data[entry['parent']] 

Et l'utilisation pour les données que vous avez fourni:

leftdata = {'10000': { 'key': '10000', 'fkey':'asdf', 'parent':'10001'}, 
       '10001': { 'key': '10001', 'fkey':'qwer', 'parent':''},} 
rightdata = {'asdf': { 'key': 'asdf', 'fkey':'10000', 'parent':'qwer'}, 
       'qwer': { 'key': 'qwer', 'fkey':'10001', 'parent':''}} 

left = Dataset(leftdata) 
right = Dataset(rightdata) 
left.set_related_dataset(right) 
right.set_related_dataset(left) 

Explication: Envelopper chaque valeur dict dans une classe Entry avec __getitem__ défini pour le rendre utilisable comme dict (plus ou Moins). Avoir une classe Dataset qui mappe les clés primaires à ces Entry s. Fournissez l'accès Entry à cet ensemble de données et fournissez des méthodes pratiques .parent() et .related().Pour que .related() fonctionne, définissez quel dataset le "lié" doit être avec set_related_dataset et tous les liens ensemble.

Maintenant, vous pouvez même juste passer Entry s et vous serez en mesure d'accéder aux entrées connexes sans avoir besoin de passer les deux jeux de données.

+0

Hmm. left ('10000'). parent(). related() plutôt sexy. Je regarderai ça plus – Xarses

2

Basé hors du commentaire de Mark Ransom, peut-être vous pouvez organiser une classe comme ceci:

class Storage(object): 

    def __init__(self): 

     self._leftdataset = { 
      '10000': { 'key': '10000', 'fkey':'asdf', 'parent':'10001'}, 
      '10001': { 'key': '10001', 'fkey':'qwer', 'parent':''} 
     } 

     self._rightdataset= { 
      'asdf': { 'key': 'asdf', 'fkey':'10000', 'parent':'qwer'}, 
      'qwer': { 'key': 'qwer', 'fkey':'10001', 'parent':''} 
     } 

    def get(self, key): 
     d1 = self._leftdataset 
     d2 = self._rightdataset 

     if key in d1: 
      left = d1[key] 
      right = d2[left['fkey']] 
     else: 
      right = d2[key] 
      left = d1[right['fkey']] 

     return left, right 

Et utiliser une seule méthode de recherche:

s = Storage() 

s.get('10000') 
# ({'fkey': 'asdf', 'key': '10000', 'parent': '10001'}, 
# {'fkey': '10000', 'key': 'asdf', 'parent': 'qwer'}) 


s.get('qwer') 
# ({'fkey': 'qwer', 'key': '10001', 'parent': ''}, 
# {'fkey': '10001', 'key': 'qwer', 'parent': ''}) 
Questions connexes