web-dev-qa-db-ja.com

Pythonでは、辞書の特定のキーの次のキーと前のキー:値を取得するにはどうすればよいですか?

さて、これは説明するのが少し難しいですが、ここに行きます:

コンテンツを追加する辞書があります。コンテンツは、ハッシュされたユーザー名(キー)とIPアドレス(値)です。私はハッシュをベース16に対して実行して、Collection.orderedDictを使用して順序に入れていました。したがって、辞書は次のようになります。

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'}

私が必要としたのは、これらのキーの1つを選択して、キー/値アイテムを1つ高く、1つ低くできるメカニズムです。したがって、たとえば、2345を選択すると、コードはkey:valueの組み合わせ「1234:8.8.8.8」と「3213:4.4.4.4」を返します。

だから、次のようなもの:

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

OrderedDictソースコード に示されているように、キーがあり、次を検索したい場合、O(1)あなたはそれをします。

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

これにより、次に、前に挿入順になります。アイテムをランダムな順序で追加する場合は、ソートされた順序でアイテムを追跡してください。

5
jamylak

編集: OPはOrderedDictsを使用していると述べていますが、ユースケースではこの種のアプローチが依然として必要です。

辞書は順序付けられていないため、これを直接行うことはできません。あなたの例では、リンクされたリストを使用するのと同じように、アイテムを参照しようとしています。

簡単な解決策は、代わりにキーを抽出してソートし、そのリストを反復処理することです。

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

keyListはアイテムの順序を保持しているので、それに戻って次/前のキーを調べ、次/前の値を取得する必要があります。また、i + 1がリストの長さより大きく、i-1が0より小さいことを確認する必要があります。

OrderedDictも同様に使用できますが、OrderedDictにはnext/prevメソッドがないため、上記とは別のリストを使用して実行する必要があると思います。

4
Adam Kerz

イテレータに基づくジェネリック関数を使用して、移動ウィンドウを取得できます( this 質問から取得):

_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
_

上記の関数をOrderedDict.items()で使用すると、3つの(キー、値)のペアが順番に表示されます。

_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
_

もちろん、この関数を使用すると、最初と最後の値が中間の位置になることは決してありません(ただし、これは、いくらかの適応で行うことは難しくないはずです)。

最大の利点は、前後のキーでテーブルを検索する必要がないこと、そして汎用的であり、あらゆる反復可能オブジェクトで機能することです。

2
Rafael Lerm

list.index()メソッドを使用することもできます。

この関数はより一般的です(位置+ nと-nを確認できます)。dictにないキーを検索する試みをキャッチし、キーの前に何もない場合はNoneも返します:

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

試してください:

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

@AdamKerzの回答のように、enumerateはPythonのようですが、初心者であれば、このコードを使用すると簡単に理解できます。

そして、ソートに続いてリストを作成してから列挙するよりも速く+小さいと思います

2
RinkyPinku

多分それはやり過ぎかもしれませんが、ヘルパークラスで挿入されたキーを追跡でき、そのリストに従って、前または次のキーを取得できます。オブジェクトが既に最初または最後の要素である場合は、境界条件を確認することを忘れないでください。この方法では、順序付けられたリストを常に並べ替えたり、要素を検索したりする必要はありません。

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

キーと値を事前に一時変数に保存し、インデックスを使用して前後のキーと値のペアにアクセスできます。

これはかなり動的であり、クエリするすべてのキーで機能します。このコードを確認してください:

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

これは lambda および list comprehension を使用して問題を解決するための素晴らしいPythonicの方法だと思いますが、実行時間では最適ではないかもしれません。

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
blueskyjunkie

シンプルで簡単なように見える別の方法:この関数はoffsetkから離れた位置にあるキーを返します

def get_shifted_key(d:dict, k:str, offset:int) -> str:
    l = list(d.keys())
    if k in l:
        i = l.index(k) + offset
        if 0 <= i < len(l):
            return l[i]
    return None    
0
Flocko Motion