さて、これは説明するのが少し難しいですが、ここに行きます:
コンテンツを追加する辞書があります。コンテンツは、ハッシュされたユーザー名(キー)と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()
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
これにより、次に、前に挿入順になります。アイテムをランダムな順序で追加する場合は、ソートされた順序でアイテムを追跡してください。
編集: 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メソッドがないため、上記とは別のリストを使用して実行する必要があると思います。
イテレータに基づくジェネリック関数を使用して、移動ウィンドウを取得できます( 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
_
もちろん、この関数を使用すると、最初と最後の値が中間の位置になることは決してありません(ただし、これは、いくらかの適応で行うことは難しくないはずです)。
最大の利点は、前後のキーでテーブルを検索する必要がないこと、そして汎用的であり、あらゆる反復可能オブジェクトで機能することです。
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)
試してください:
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のようですが、初心者であれば、このコードを使用すると簡単に理解できます。
そして、ソートに続いてリストを作成してから列挙するよりも速く+小さいと思います
多分それはやり過ぎかもしれませんが、ヘルパークラスで挿入されたキーを追跡でき、そのリストに従って、前または次のキーを取得できます。オブジェクトが既に最初または最後の要素である場合は、境界条件を確認することを忘れないでください。この方法では、順序付けられたリストを常に並べ替えたり、要素を検索したりする必要はありません。
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
キーと値を事前に一時変数に保存し、インデックスを使用して前後のキーと値のペアにアクセスできます。
これはかなり動的であり、クエリするすべてのキーで機能します。このコードを確認してください:
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]
これは 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
シンプルで簡単なように見える別の方法:この関数は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