it-swarm.com.de

Wie kann ich in Python den nächsten und vorherigen Schlüssel abrufen: den Wert eines bestimmten Schlüssels in einem Wörterbuch?

Okay, das ist ein bisschen schwer zu erklären, aber hier ist es:

Ich habe ein Wörterbuch, zu dem ich Inhalte hinzufüge. Der Inhalt ist ein gehashter Benutzername (Schlüssel) mit einer IP-Adresse (Wert). Ich habe die Hashes in eine Reihenfolge gebracht, indem ich sie auf Basis 16 ausgeführt und dann Collection.orderedDict verwendet habe. Das Wörterbuch sah also ungefähr so ​​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 brauchte, war ein Mechanismus, der es mir ermöglichte, einen dieser Schlüssel auszuwählen und den Schlüssel-/Wertgegenstand um einen höheren und einen niedrigeren zu erhalten. Wenn ich beispielsweise 2345 auswählen würde, würde der Code die Tastenkombinationen '1234: 8.8.8.8' und '3213: 4.4.4.4' zurückgeben.

So etwas wie:

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

Wie aus dem OrderedDict-Quellcode ersichtlich, , Wenn Sie einen Schlüssel haben und den nächsten und den vorigen in O(1) suchen möchten, gehen Sie wie folgt vor.

>>> 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 als nächstes und vorrangig durch die Reihenfolge des Einfügens geben. Wenn Sie Artikel in zufälliger Reihenfolge hinzufügen, verfolgen Sie einfach Ihre Artikel in sortierter Reihenfolge. 

4
jamylak

Sie können eine generische Funktion verwenden, die auf Iteratoren basiert, um ein sich bewegendes Fenster (aus this question) 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

Wenn Sie die obige Funktion mit OrderedDict.items() verwenden, erhalten Sie drei Paare (Schlüssel, Wert) 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 werden bei dieser Funktion der erste und der letzte Wert niemals in der mittleren Position sein (obwohl dies bei Anpassungen nicht schwierig sein sollte).

Ich denke, der größte Vorteil ist, dass es keine Tabellensuche in den vorherigen und nächsten Schlüsseln erfordert und dass es generisch ist und mit allen Iterationen funktioniert.

2
Rafael Lerm

Edit: OP gibt jetzt an, dass sie OrderedDicts verwenden, der Anwendungsfall erfordert jedoch noch einen solchen Ansatz.

Da Diktate nicht angeordnet sind, können Sie dies nicht direkt tun. In Ihrem Beispiel versuchen Sie, auf das Element zu verweisen, als würden Sie eine verknüpfte Liste verwenden.

Eine schnelle Lösung wäre stattdessen, die Schlüssel zu extrahieren und sie zu sortieren, dann diese Liste zu durchlaufen:

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

Die Variable keyList enthält die Reihenfolge Ihrer Elemente und Sie müssen zurückgehen, um herauszufinden, was der nächste/vorherige Schlüssel ist, um den nächsten/vorherigen Wert zu erhalten. Sie müssen auch prüfen, ob i + 1 größer als die Listenlänge ist und i-1 kleiner als 0 ist.

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

2
Adam Kerz

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

Diese Funktion ist allgemeiner (Sie können die Positionen + n und -n überprüfen), fängt Versuche ab, einen Schlüssel zu suchen, der nicht im Diktat enthalten ist, und gibt auch None zurück, wenn nach dem Schlüssel nichts vor steht:

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)
1
Roberto

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])

In @ AdamKerzs Antwort scheint enumerate Pythonic zu sein, aber wenn Sie ein Anfänger sind, kann dieser Code Ihnen helfen, ihn auf einfache Weise zu verstehen.

Und ich denke, es ist schneller + kleiner im Vergleich zum Sortieren, gefolgt vom Erstellen der Liste und dem Aufzählen

1
RinkyPinku

Vielleicht ist es ein Overkill, aber Sie können den Überblick über die mit einer Hilfsklasse eingegebenen Schlüssel behalten, und entsprechend dieser Liste können Sie den Schlüssel für Zurück oder Weiter abrufen. Vergessen Sie nicht, auf Randbedingungen zu prüfen, ob die Objekte bereits das erste oder letzte Element sind. Auf diese Weise müssen Sie nicht immer die geordnete Liste neu sortieren 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
user1767754

Sie können die Schlüssel und Werte in der vorläufigen temporären Variable speichern und über Index auf das vorherige und das nächste Wertepaar zugreifen. 

Es ist ziemlich dynamisch und 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]
1
user123

Ich denke, dies ist ein Nice Pythonic-Weg, um Ihr Problem mit einem Lambda und List-Verständnis zu lösen, obwohl es in der Ausführungszeit möglicherweise nicht optimal ist:

import collections

x = collections.OrderedDict([('a','v1'),('b','v2'),('c','v3'),('d','v4')])

previousItem = lambda currentKey, thisOrderedDict : [
    list( thisOrderedDict.items() )[ z - 1 ] if (z != 0) else None
    for z in range( len( thisOrderedDict.items() ) )
    if (list( thisOrderedDict.keys() )[ z ] == currentKey) ][ 0 ]

nextItem = lambda currentKey, thisOrderedDict : [
    list( thisOrderedDict.items() )[ z + 1 ] if (z != (len( thisOrderedDict.items() ) - 1)) else None
    for z in range( len( thisOrderedDict.items() ) )
    if (list( thisOrderedDict.keys() )[ z ] == currentKey) ][ 0 ]

assert previousItem('c', x) == ('b', 'v2')
assert nextItem('c', x) == ('d', 'v4')
assert previousItem('a', x) is None
assert nextItem('d',x) is None
0
Russell