111 votes

Intersection de deux dictionnaires

Je travaille sur un programme de recherche sur un index inversé. L'index lui-même est un dictionnaire dont les clés sont des termes et dont les valeurs sont elles-mêmes des dictionnaires de documents courts, avec des numéros d'identification comme clés et leur contenu textuel comme valeurs.

Pour effectuer une recherche "ET" sur deux termes, je dois donc croiser leurs listes d'affichages (dictionnaires). Quelle est une façon claire (et pas nécessairement très intelligente) de faire cela en Python ? J'ai commencé par essayer la méthode longue avec iter :

p1 = index[term1]  
p2 = index[term2]
i1 = iter(p1)
i2 = iter(p2)
while ...  # not sure of the 'iter != end 'syntax in this case
...

3voto

soldovskij Points 131

Pour trouver l'intersection complète par les clés et les valeurs

d1 = {'a':1}
d2 = {'b':2, 'a':1}
{x:d1[x] for x in d1 if x in d2 and d1[x] == d2[x]}

>> {'a':1}

2voto

thodnev Points 950

Bon, voici une version généralisée du code ci-dessus en Python3. Il est optimisé pour utiliser les compréhensions et les vues dict de type set qui sont assez rapides.

La fonction intersecte un nombre arbitraire de dicts et retourne un dict avec des clés communes et un ensemble de valeurs communes pour chaque clé commune :

def dict_intersect(*dicts):
    comm_keys = dicts[0].keys()
    for d in dicts[1:]:
        # intersect keys first
        comm_keys &= d.keys()
    # then build a result dict with nested comprehension
    result = {key:{d[key] for d in dicts} for key in comm_keys}
    return result

Exemple d'utilisation :

a = {1: 'ba', 2: 'boon', 3: 'spam', 4:'eggs'}
b = {1: 'ham', 2:'baboon', 3: 'sausages'}
c = {1: 'more eggs', 3: 'cabbage'}

res = dict_intersect(a, b, c)
# Here is res (the order of values may vary) :
# {1: {'ham', 'more eggs', 'ba'}, 3: {'spam', 'sausages', 'cabbage'}}

Ici, les valeurs du dict doivent être hachables, si elles ne le sont pas, vous pouvez simplement changer les parenthèses { } en liste [ ] :

result = {key:[d[key] for d in dicts] for key in comm_keys}

1voto

JCode Points 183

Votre question n'est pas assez précise pour donner une réponse unique.

1. Intersection clé

Si vous voulez intersecter ID à partir de postes ( crédits à James ) font :

common_ids = p1.keys() & p2.keys()

Cependant, si vous voulez itérer des documents, vous devez considérer quel poste a une priorité, je suppose que c'est p1 . Pour itérer les documents pour common_ids , collections.ChainMap sera des plus utiles :

from collections import ChainMap
intersection = {id: document
                for id, document in ChainMap(p1, p2)
                if id in common_ids}
for id, document in intersection:
    ...

Ou si vous ne voulez pas créer des fichiers séparés. intersection dictionnaire :

from collections import ChainMap
posts = ChainMap(p1, p2)
for id in common_ids:
    document = posts[id]

2. Articles Intersection

Si vous voulez intersecter articles des deux postes, ce qui revient à faire correspondre ID et les documents, utilisez le code ci-dessous ( crédits à la DCPY ). Toutefois, cela n'est utile que si vous recherchez des doublons dans les termes.

duplicates = dict(p1.items() & p2.items())
for id, document in duplicates:
    ...

3. Faire un itération sur p1 "ET p2 .

Dans le cas où par " Recherche "ET". " et en utilisant iter vous vouliez chercher les deux postes puis à nouveau collections.ChainMap est le meilleur moyen d'itérer sur (presque) tous les éléments de plusieurs messages :

from collections import ChainMap
for id, document in ChainMap(p1, p2):
    ...

0voto

Eric Urban Points 1460

Il suffit d'envelopper les instances du dictionnaire avec une simple classe qui obtient les deux valeurs que vous voulez

class DictionaryIntersection(object):
    def __init__(self,dictA,dictB):
        self.dictA = dictA
        self.dictB = dictB

    def __getitem__(self,attr):
        if attr not in self.dictA or attr not in self.dictB:
            raise KeyError('Not in both dictionaries,key: %s' % attr)

        return self.dictA[attr],self.dictB[attr]

x = {'foo' : 5, 'bar' :6}
y = {'bar' : 'meow' , 'qux' : 8}

z = DictionaryIntersection(x,y)

print z['bar']

0voto

Aaron Goldman Points 579
def two_keys(term_a, term_b, index):
    doc_ids = set(index[term_a].keys()) & set(index[term_b].keys())
    doc_store = index[term_a] # index[term_b] would work also
    return {doc_id: doc_store[doc_id] for doc_id in doc_ids}

def n_keys(terms, index):
    doc_ids = set.intersection(*[set(index[term].keys()) for term in terms])
    doc_store = index[term[0]]
    return {doc_id: doc_store[doc_id] for doc_id in doc_ids}

In [0]: index = {'a': {1: 'a b'}, 
                 'b': {1: 'a b'}}

In [1]: two_keys('a','b', index)
Out[1]: {1: 'a b'}

In [2]: n_keys(['a','b'], index)
Out[2]: {1: 'a b'}

Je vous recommande de changer votre index de

index = {term: {doc_id: doc}}

à deux index, un pour les termes et un autre pour les valeurs.

term_index = {term: set([doc_id])}
doc_store = {doc_id: doc}

de cette façon, vous ne stockez pas plusieurs copies des mêmes données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X