2015-01-19 5 views
10

Okay, das ist ein bisschen schwer zu erklären, aber hier gehts:In Python, Wie bekomme ich den nächsten und vorherigen Schlüssel: Wert eines bestimmten Schlüssels in einem Wörterbuch?

Ich habe ein Wörterbuch, dem ich Inhalt hinzufügen. Der Inhalt ist ein Hash-Benutzername (Schlüssel) mit einer IP-Adresse (Wert). Ich habe die Hashes in eine Reihenfolge gebracht, indem ich sie auf Basis 16 ausgeführt habe und dann Collection.orderedDict verwendet habe. So sah das Wörterbuch ein wenig wie folgt aus:

d = {'1234': '8.8.8.8', '2345':'0.0.0.0', '3213':'4.4.4.4', '4523':'1.1.1.1', '7654':'1.3.3.7', '9999':'127.0.0.1'} 

Was ich ein Mechanismus benötigt war, die mir erlauben würde einer dieser Schlüssel zu holen, und der Schlüssel/Wert-Element eine höhere und eine niedrigere erhalten. So zum Beispiel, wenn ich 2345 zu holen, würde zurückkehrt der Code der Schlüssel: Wertekombinationen '1234: 8.8.8.8' und '3213: 4.4.4.4'

Also, so etwas wie:

for i in d: 
    while i < len(d) 
    if i == '2345': 
    print i.nextItem 
    print i.previousItem 
    break() 
+5

DICTS sind nicht bestellt. Es gibt keinen nächsten oder vorherigen Artikel. –

+0

Ich habe meine bestellt mit 'collections.orderedDict'. Wenn es keine Möglichkeit gibt, dies in einem Diktat zu tun, kann ich die Schlüssel herausnehmen und in eine Liste (oder ein Tupel oder was auch immer) einfügen und dann nach dem nächsten und vorherigen Element suchen und dieses dann verwenden das Wörterbuch nach ihren Werten erneut abfragen? – Brewer

+0

'collections.OrderedDict' Objekte haben intern eine Liste von 2-Tupeln. Wenn Sie sie mit '.items()' durchlaufen, sollten Sie sie in der Reihenfolge erhalten, in der sie hinzugefügt werden. – metatoaster

Antwort

1

Bearbeiten: OP gibt jetzt an, dass sie OrderedDicts verwenden, aber der Anwendungsfall erfordert immer noch diese Art von Ansatz.

Da dicts nicht bestellt werden, können Sie dies nicht direkt tun. In Ihrem Beispiel versuchen Sie, das Objekt so zu referenzieren, als würden Sie eine verknüpfte Liste verwenden.

würde Eine schnelle Lösung anstelle werden die Schlüssel zu extrahieren und sortieren sie über diese Liste dann iterieren:

keyList=sorted(d.keys()) 
for i,v in enumerate(keyList): 
    if v=='eeee': 
     print d[keyList[i+1]] 
     print d[keyList[i-1]] 

Die keyList die Reihenfolge der Elemente hält, und Sie haben wieder zu ihm gehen, um herauszufinden, was Der nächste/vorherige Schlüssel ist der nächste/vorherige Wert. Sie müssen auch überprüfen, ob i + 1 größer als die Listenlänge und i-1 kleiner als 0 ist.

Sie können ein OrderedDict in ähnlicher Weise verwenden, aber ich glaube, dass Sie das oben genannte mit einer separaten Liste als tun müssen OrderedDict hat keine next/prev-Methoden.

1

Versuchen:

pos = 0 
d = {'aaaa': 'a', 'bbbb':'b', 'cccc':'c', 'dddd':'d', 'eeee':'e', 'ffff':'f'} 

for i in d: 
    pos+=1 
    if i == 'eeee': 
     listForm = list(d.values()) 
     print(listForm[pos-1]) 
     print(listForm[pos+1]) 

Wie in @ AdamKerz Antwort enumerate scheint pythonic, aber wenn Sie ein Anfänger dieser Code sind könnte Ihnen helfen, es auf einfache Art und Weise zu verstehen.

Und ich denke, sein schnelles + kleiner im Vergleich zu durch & dann

Aufzählen Gebäude Liste gefolgt Sortierung
+0

Hinweis das funktioniert nur, wenn Sie tatsächlich ein OrderedDict verwenden ... :-) Und Sie erstellen auch eine Liste dort: list (d.values ​​()). Und möglicherweise mehrere Listen, wenn die Bedingung mehr als einen Schlüssel entspricht (nein, wird es in diesem Beispiel nicht). Beachten Sie, dass Sortiert eine Liste erstellt (dies ist jedoch notwendig, wenn Sie an einer alphabetischen Reihenfolge interessiert sind und nicht an der Reihenfolge, wie dies bei der ursprünglichen Anfrage der Fall war). Und schließlich gibt enumerate einen Iterator zurück, so dass im Grunde dasselbe in Bezug auf Effizienz wie das, was Sie tun, und weniger ausführlich ist. –

+0

@AdamKerz k, danke für die Einblicke - – aim100k

1

Sie könnten auch die list.index() Methode verwenden.

Diese Funktion ist generischer (Sie können die Positionen + n und -n prüfen), es wird versucht, einen Schlüssel zu suchen, der nicht im dict ist, und None wird zurückgegeben, wenn vor dem Schlüssel nichts ist:

def keyshift(dictionary, key, diff): 
    if key in dictionary: 
     token = object() 
     keys = [token]*(diff*-1) + sorted(dictionary) + [token]*diff 
     newkey = keys[keys.index(key)+diff] 
     if newkey is token: 
      print None 
     else: 
      print {newkey: dictionary[newkey]} 
    else: 
     print 'Key not found' 


keyshift(d, 'bbbb', -1) 
keyshift(d, 'eeee', +1) 
+0

Das ist auch gut, ich denke, die Verwendung sollte berücksichtigt werden, wenn der Zugriff auf prev/next Element sehr oft passieren wird oder wie oft die Einfügungen in das Wörterbuch passieren. – user1767754

1

Vielleicht ist es ein viel des Guten, aber Sie können verfolgen, den Schlüssel mit einem Hilfsklasse eingeführt und auf diese Liste nach, können Sie den Schlüssel für die Zurück- oder Weiter abzurufen. Vergessen Sie nicht, nach Randbedingungen zu suchen, wenn das Objekt bereits das erste oder letzte Element ist. Auf diese Weise müssen Sie nicht immer die geordnete Liste aufrufen oder nach dem Element suchen.

from collections import OrderedDict 

class Helper(object): 
    """Helper Class for Keeping track of Insert Order""" 
    def __init__(self, arg): 
     super(Helper, self).__init__() 

    dictContainer = dict() 
    ordering = list() 

    @staticmethod 
    def addItem(dictItem): 
     for key,value in dictItem.iteritems(): 
      print key,value 
      Helper.ordering.append(key) 
      Helper.dictContainer[key] = value 

    @staticmethod 
    def getPrevious(key): 
     index = (Helper.ordering.index(key)-1) 
     return Helper.dictContainer[Helper.ordering[index]] 


#Your unordered dictionary 
d = {'aaaa': 'a', 'bbbb':'b', 'cccc':'c', 'dddd':'d', 'eeee':'e', 'ffff':'f'} 

#Create Order over keys 
ordered = OrderedDict(sorted(d.items(), key=lambda t: t[0])) 

#Push your ordered list to your Helper class 
Helper.addItem(ordered) 


#Get Previous of  
print Helper.getPrevious('eeee') 
>>> d 
1

Sie eine generische Funktion, basierend auf Iteratoren verwenden könnte, ein sich bewegendes Fenster (von this Frage genommen) zu erhalten:

import itertools 

def window(iterable, n=3): 
    it = iter(iterable) 
    result = tuple(itertools.islice(it, n)) 
    if len(result) == n: 
     yield result 
    for element in it: 
     result = result[1:] + (element,) 
     yield result 

l = range(8) 
for i in window(l, 3): 
    print i 

die obige Funktion mit OrderedDict.items() Verwendung finden Sie drei (Schlüssel geben, Wert) -Paare in der Reihenfolge:

d = collections.OrderedDict(...) 

for p_item, item, n_item in window(d.items()): 
    p_key, p_value = p_item 
    key, value = item 
    # Or, if you don't care about the next value: 
    n_key, _ = n_item 

natürlich diese Funktion die ersten und letzten Werte in der mittleren Position wird nie (obwohl dies verwenden sollten nicht mit etwas Anpassung schwierig sein).

Ich denke, der größte Vorteil ist, dass es keine Tabellen-Lookups in den vorherigen und nächsten Tasten benötigt, und auch, dass es generisch ist und mit jedem iterablen funktioniert.

3

Wie in der OrderedDict source code, zu sehen, wenn Sie einen Schlüssel haben und Sie die nächste und prev in O (1) finden möchten, hier ist, wie Sie das tun.

>>> from collections import OrderedDict 
>>> d = OrderedDict([('aaaa', 'a',), ('bbbb', 'b'), ('cccc', 'c'), ('dddd', 'd'), ('eeee', 'e'), ('ffff', 'f')]) 
>>> i = 'eeee' 
>>> link_prev, link_next, key = d._OrderedDict__map['eeee'] 
>>> print 'nextKey: ', link_next[2], 'prevKey: ', link_prev[2] 
nextKey: ffff prevKey: dddd 

Dies wird Ihnen nächste und vorherige nach Anzeigenreihenfolge geben. Wenn Sie Artikel in zufälliger Reihenfolge hinzufügen, behalten Sie Ihre Artikel in sortierter Reihenfolge im Auge.

+1

Das ist keine gute Übung - __map ist ein privates Attribut und es ist nicht garantiert, dass es in verschiedenen Versionen oder auf verschiedenen Plattformen genauso funktioniert oder funktioniert. –

+0

@AdamKerz Es ist der einzige Weg, um auf die 'OrderedDict'-Liste zuzugreifen, wenn Sie sie zu welchem ​​Zweck auch immer benötigen, Sie brauchen das, wenn Sie das' next' und 'prev' in O (1) suchen wollen . Denken Sie daran, ich antwortete auf die eigentliche Frage, und der Titel war irreführend für das eigentliche Problem OP ist – jamylak

+0

Ich habe nie gesagt, dass es nicht funktioniert, oder dass es eine andere Möglichkeit, Zugriff auf OrderedDict's verknüpfte Liste, nur, dass es ist keine gute Praxis. Das OP erwähnte O (1) -Komplexität nie, und dennoch ist meine Lösung auch allgemein O (1) -Komplexität (vorausgesetzt, dict-Lookup ist O (1) oder ähnlich wie in normalen Fällen). –

1

Sie können die Schlüssel und Werte in der Temp-Variable in previous speichern und mit index auf das vorherige und nächste Schlüssel/Wert-Paar zugreifen.

Es ist ziemlich dynamisch, funktioniert für jeden Schlüssel, den Sie abfragen. Bitte überprüfen Sie diesen Code:

d = {'1234': '8.8.8.8', '2345':'0.0.0.0', '3213':'4.4.4.4', '4523':'1.1.1.1', '7654':'1.3.3.7', '9999':'127.0.0.1'} 
ch = raw_input('Pleasure Enter your choice : ') 
keys = d.keys() 
values = d.values() 
#print keys, values 
for k,v in d.iteritems(): 
    if k == ch: 
     ind = d.keys().index(k) 
     print keys[ind-1], ':',values[ind-1] 
     print keys[ind+1], ':',values[ind+1] 
Verwandte Themen