在 Python 中,如何获取下一个和上一个键:字典中特定键的值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28035490/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 02:38:50  来源:igfitidea点击:

In Python, How can I get the next and previous key:value of a particular key in a dictionary?

pythondictionarykey

提问by Brewer

Okay, so this is a little hard to explain, but here goes:

好的,所以这有点难以解释,但这里是:

I have a dictionary, which I'm adding content to. The content is a hashed username (key) with an IP address (value). I was putting the hashes into an order by running them against base 16, and then using Collection.orderedDict. So, the dictionary looked a little like this:

我有一本字典,我正在向其中添加内容。内容是带有 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'}

What I needed was a mechanism that would allow me to pick one of those keys, and get the key/value item one higher and one lower. So, for example, If I were to pick 2345, the code would return the key:value combinations '1234:8.8.8.8' and '3213:4.4.4.4'

我需要的是一种机制,可以让我选择其中一个键,并让键/值项一个高一个低。因此,例如,如果我选择 2345,代码将返回键:值组合 '1234:8.8.8.8' 和 '3213:4.4.4.4'

So, something like:

所以,像这样:

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

回答by Adam Kerz

Edit:OP now states that they are using OrderedDicts but the use case still requires this sort of approach.

编辑:OP 现在声明他们正在使用 OrderedDicts,但用例仍然需要这种方法。

Since dicts are not ordered you cannot directly do this. From your example, you are trying to reference the item like you would use a linked list.

由于 dicts 不是有序的,因此您不能直接执行此操作。从您的示例中,您正在尝试像使用链接列表一样引用该项目。

A quick solution would be instead to extract the keys and sort them then iterate over that list:

一个快速的解决方案是提取键并对它们进行排序,然后迭代该列表:

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

The keyListholds the order of your items and you have to go back to it to find out what the next/previous key is to get the next/previous value. You also have to check for i+1 being greater than the list length and i-1 being less than 0.

keyList握着你的项目的顺序,你必须回去吧,找出一个/上一个关键是要获得下一个/前值是什么。您还必须检查 i+1 是否大于列表长度以及 i-1 是否小于 0。

You can use an OrderedDict similarly but I believe that you still have to do the above with a separate list as OrderedDict doesn't have next/prev methods.

您可以类似地使用 OrderedDict,但我相信您仍然必须使用单独的列表执行上述操作,因为 OrderedDict 没有 next/prev 方法。

回答by RinkyPinku

Try:

尝试:

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

As in @AdamKerz's answer enumerateseems pythonic, but if you are a beginner this code might help you understand it in an easy way.

正如@AdamKerz 的回答enumerate似乎是Pythonic ,但如果您是初学者,此代码可能会帮助您以简单的方式理解它。

And I think its faster + smaller compared to sorting followed by building list & then enumerating

而且我认为与排序然后构建列表然后枚举相比它更快+更小

回答by Roberto

You could also use the list.index()method.

您也可以使用该list.index()方法。

This function is more generic (you can check positions +n and -n), it will catch attempts at searching a key that's not in the dict, and it will also return Noneif there's nothing before of after the key:

此函数更通用(您可以检查位置 +n 和 -n),它将捕获搜索不在字典中的键的尝试,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)

回答by user1767754

Maybe it is an overkill, but you can keep Track of the Keys inserted with a Helper Class and according to that list, you can retrieve the Key for Previous or Next. Just don't forget to check for border conditions, if the objects is already first or last element. This way, you will not need to always resort the ordered list or search for the element.

也许这有点矫枉过正,但是您可以使用 Helper 类保持对插入的键的跟踪,并且根据该列表,您可以检索上一个或下一个的键。如果对象已经是第一个或最后一个元素,请不要忘记检查边界条件。这样,您就不需要总是使用有序列表或搜索元素。

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

回答by Rafael Lerm

You could use a generic function, based on iterators, to get a moving window (taken from thisquestion):

您可以使用基于迭代器的通用函数来获取移动窗口(取自问题):

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

Using the above function with OrderedDict.items()will give you three (key, value) pairs, in order:

使用上面的函数 withOrderedDict.items()将为您提供三个(键,值)对,依次为:

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

Of course using this function the first and last values will never be in the middle position (although this should not be difficult to do with some adaptation).

当然,使用这个函数,第一个和最后一个值永远不会在中间位置(尽管通过一些调整应该不难做到)。

I think the biggest advantage is that it does not require table lookups in the previous and next keys, and also that it is generic and works with any iterable.

我认为最大的优点是它不需要在上一个和下一个键中查找表,而且它是通用的并且适用于任何可迭代对象。

回答by jamylak

As seen in the OrderedDictsource code, if you have a key and you want to find the next and prev in O(1) here's how you do that.

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

This will give you next and prev by insertion order. If you add items in random order then just keep track of your items in sorted order.

这将按插入顺序为您提供下一个和上一个。如果您以随机顺序添加项目,则只需按排序顺序跟踪您的项目。

回答by user123

You can store the keys and values in temp variable in prior, and can access previous and next key,value pair using index.

您可以预先将键和值存储在临时变量中,并且可以使用索引访问上一个和下一个键值对。

It is pretty dynamic, will work for any key you query. Please check this 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]

回答by blueskyjunkie

I think this is a nice Pythonic way of resolving your problem using a lambdaand list comprehension, although it may not be optimal in execution time:

我认为这是使用lambdalist 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

回答by Flocko Motion

Another way that seems simple and straight forward: this function returns the key which is offsetpositions away from k

另一种看起来简单直接的方法:此函数返回远离k 的偏移位置的键

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