Ich arbeite an einem Suchprogramm über einen invertierten Index. Der Index selbst ist ein Wörterbuch, dessen Schlüssel Begriffe und dessen Werte selbst Wörterbücher für kurze Dokumente sind, mit ID-Nummern als Schlüssel und deren Textinhalt als Werte.
Um eine UND-Suche nach zwei Begriffen durchzuführen, muss ich daher deren Posting-Listen (Wörterbücher) schneiden. Was ist ein klarer (nicht unbedingt übermäßig kluger) Weg, dies in Python zu tun? Ich begann damit, es lange zu versuchen mit iter
:
p1 = index[term1]
p2 = index[term2]
i1 = iter(p1)
i2 = iter(p2)
while ... # not sure of the 'iter != end 'syntax in this case
...
python
dictionary
iteration
intersection
Nicole
quelle
quelle
{term:{doc_id:p1[term][doc_id] for doc_id in p1[term] if doc_id in p2[term]} for term in p1 if term in p2}
Antworten:
In Python verwenden Sie den
&
Operator , um den Schnittpunkt von Mengen zu berechnen, und Wörterbuchschlüssel sind satzähnliche Objekte (in Python 3):dict_a = {"a": 1, "b": 2} dict_b = {"a": 2, "c": 3} intersection = dict_a.keys() & dict_b.keys() # {'a'}
In Python 2 müssen Sie die Wörterbuchschlüssel in Sets selbst konvertieren:
keys_a = set(dict_a.keys()) keys_b = set(dict_b.keys()) intersection = keys_a & keys_b
quelle
Eine wenig bekannte Tatsache ist, dass Sie dazu keine
set
s konstruieren müssen:In Python 2:
In [78]: d1 = {'a': 1, 'b': 2} In [79]: d2 = {'b': 2, 'c': 3} In [80]: d1.viewkeys() & d2.viewkeys() Out[80]: {'b'}
In Python 3 ersetzen Sie
viewkeys
durchkeys
; Gleiches gilt fürviewvalues
undviewitems
.Aus der Dokumentation von
viewitems
:In [113]: d1.viewitems?? Type: builtin_function_or_method String Form:<built-in method viewitems of dict object at 0x64a61b0> Docstring: D.viewitems() -> a set-like object providing a view on D's items
Für größere
dict
s ist dies auch etwas schneller alsset
s zu konstruieren und sie dann zu schneiden:In [122]: d1 = {i: rand() for i in range(10000)} In [123]: d2 = {i: rand() for i in range(10000)} In [124]: timeit d1.viewkeys() & d2.viewkeys() 1000 loops, best of 3: 714 µs per loop In [125]: %%timeit s1 = set(d1) s2 = set(d2) res = s1 & s2 1000 loops, best of 3: 805 µs per loop For smaller `dict`s `set` construction is faster: In [126]: d1 = {'a': 1, 'b': 2} In [127]: d2 = {'b': 2, 'c': 3} In [128]: timeit d1.viewkeys() & d2.viewkeys() 1000000 loops, best of 3: 591 ns per loop In [129]: %%timeit s1 = set(d1) s2 = set(d2) res = s1 & s2 1000000 loops, best of 3: 477 ns per loop
Wir vergleichen hier Nanosekunden, die für Sie möglicherweise von Bedeutung sind oder nicht. In jedem Fall erhalten Sie ein zurück
set
, so dass die Verwendung vonviewkeys
/keys
ein bisschen Unordnung beseitigt.quelle
viewkeys()
ist "Neu in Version 2.7"set(d1.keys()) & set(d2.keys())
Methode. Ich verstehe jedoch nicht, warum das so ist.pip install future
) -Paket funktioniert Folgendes in Python 2 und 3:from future.utils import viewkeys; viewkeys(d1) & viewkeys(d2)
In [1]: d1 = {'a':1, 'b':4, 'f':3} In [2]: d2 = {'a':1, 'b':4, 'd':2} In [3]: d = {x:d1[x] for x in d1 if x in d2} In [4]: d Out[4]: {'a': 1, 'b': 4}
quelle
In Python 3 können Sie verwenden
intersection = dict(dict1.items() & dict2.items()) union = dict(dict1.items() | dict2.items()) difference = dict(dict1.items() ^ dict2.items())
quelle
dict1 = {1: 1, 2:2}
unddict2 = {2:4, 3:3}
dasintersection == set()
. Wahrscheinlich ist dies nicht das, was OP will.intersection = dict(...)
wandelt es wieder in a umdict
. Außerdem habe ich es gerade mitdict1 = {1: 1, 2: 2}
unddict2 = {2: 4, 3: 3}
(den obigen Wörterbüchern) getestet undintersection == set()
istFalse
. Es ist ein leeres Wörterbuch.dict(...)
. Der Punkt ist, dass in meinem Beispiel das Ergebnis leer ist. Wenn man bedenkt, welche OP-akzeptierten und häufigeren Anwendungsfälle sich überschneiden,.items()
ist dies nur dann sinnvoll, wenn Sie nach wörtlichen Duplikaten suchen.dict1
verwenden{v: k for k, v in dict1.items()}
und stattdict2
verwenden{v: k for k, v in dict2.items()}
. Wenn Sie den Fall möchten, in dem es sich entweder um den Schlüssel oder das Wörterbuch handelt, verwenden Sie die Vereinigung der in der Antwort angegebenen Schnittmenge und der in diesem Kommentar angegebenen Schnittmenge.Schließen Sie die Wörterbuchinstanzen einfach mit einer einfachen Klasse ein, die beide gewünschten Werte erhält
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']
quelle
Okay, hier ist eine verallgemeinerte Version des obigen Codes in Python3. Es ist optimiert, um Verständnisse und satzartige Diktatansichten zu verwenden, die schnell genug sind.
Die Funktion schneidet beliebig viele Dikte und gibt ein Dikt mit gemeinsamen Schlüsseln und einer Reihe gemeinsamer Werte für jeden gemeinsamen Schlüssel zurück:
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
Anwendungsbeispiel:
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'}}
Hier müssen die diktierten Werte hashbar sein. Wenn dies nicht der Fall ist, können Sie einfach die Klammern {} in list [] ändern:
result = {key:[d[key] for d in dicts] for key in comm_keys}
quelle
*dicts
Als Funktionsargumente müssen Sie zahlreiche Argumente übergeben, keine Liste davon. Wenn Sie die Listelst = [dict1, dict2, dict3, ...]
entweder verwendendict_intersect(dict1, dict2, dict3, ...)
oder entpacken müssendict_intersect(*lst)
Ihre Frage ist nicht präzise genug, um eine einzige Antwort zu geben.
1. Schlüsselkreuzung
Wenn Sie
ID
s von Posts ( Credits an James ) überschneiden möchten, gehen Sie wie folgt vor :Wenn Sie jedoch Dokumente iterieren möchten, müssen Sie berücksichtigen, welcher Beitrag Priorität hat. Ich gehe davon aus, dass dies der Fall ist
p1
. Das Iterieren von Dokumenten fürcommon_ids
istcollections.ChainMap
am nützlichsten:from collections import ChainMap intersection = {id: document for id, document in ChainMap(p1, p2) if id in common_ids} for id, document in intersection: ...
Oder wenn Sie kein separates
intersection
Wörterbuch erstellen möchten :from collections import ChainMap posts = ChainMap(p1, p2) for id in common_ids: document = posts[id]
2. Elemente Schnittpunkt
Wenn Sie Elemente beider Beiträge überschneiden möchten , dh
ID
s und Dokumente abgleichen möchten , verwenden Sie den folgenden Code ( Gutschriften für DCPY ). Dies ist jedoch nur dann nützlich, wenn Sie nach Duplikaten suchen.duplicates = dict(p1.items() & p2.items()) for id, document in duplicates: ...
3. Iterieren Sie über
p1
'UND'p2
.Wenn Sie mit " UND" suchen und beide Beiträge
iter
durchsuchen möchten, ist es am besten, (fast) alle Elemente in mehreren Beiträgen zu durchlaufen:collections.ChainMap
from collections import ChainMap for id, document in ChainMap(p1, p2): ...
quelle
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'}
Ich würde empfehlen, Ihren Index von zu ändern
auf zwei Indizes, einen für die Begriffe und dann einen separaten Index für die Werte
term_index = {term: set([doc_id])} doc_store = {doc_id: doc}
Auf diese Weise speichern Sie nicht mehrere Kopien derselben Daten
quelle