简体   繁体   中英

Get an object in a sortedcontainers.SortedKeyList using a different key

Let's say I have an Item with the following definition:

Item(id: str, sequence: int)

id is a random string of characters.

sequence is the number representing the order that the Item was put into the data structure.


I wanted to organize all Item objects in some data structure that maintains the order of Item based on its sequence . So I used a SortedKeyList with they key set to sequence .

import sortedcontainers

items = sortedcontainers.SortedKeyList(key=lambda x: x.sequence)

For most operations, this works fine. But the issue is that I have an operation that would need to get the Item with a specific id , but there is no way to do that using the key above.

I would like to do something like:

items.add(Item('abc', 0))
items.add(Item('www', 1))
items.add(Item('zyx', 2))

# This should be the 2nd item added.
item = items['www']

Additional info :

The operation I intended to add would need to be able to return N number of Item starting from a specific id .

load_n_items_from_id(num: int, id: str) -> [Item]

Using the example above, this method should return the following result:

loaded = load_n_items_from_id(2, 'www')
# loaded should contain [Item('www', 1), Item('zyx', 2)]

The question if I am not wrong is simply interested in maintaining the order at which I am inserting the element, if that's the case we can simply make use of built in function OrderedDictionary https://docs.python.org/3/library/collections.html#ordereddict-objects rather than installing sortedcontainers via pip.

from collections import OrderedDict

items= OrderedDict()
#Items can be inserted according to your convenience either by loop or manually
items['abc']=0
items['www']=1
items['zyx']=2

print(items) #Prints dictionary in the given order

Don't forget to accept the answer if it helped, if anymore doubts, you may drop the comment. Infact I guess you can even use normal dictionary(Unordered) if all you want is the value of the corresponding key which you already have given while giving the input.

Given:

import sortedcontainers


class Item(object):
    def __init__(self, ident: str, sequence: int):
        self.ident = ident
        self.sequence = sequence

    def __repr__(self):
        return f"<Item id={self.ident} sequence={self.sequence}>"


items = sortedcontainers.SortedKeyList(key=lambda x: x.sequence)
items.add(Item("abc", 0))
items.add(Item("www", 1))
items.add(Item("zyx", 2))

To find the item will require O(n) complexity, because you are searching by something that it is not sorted by. Simplest way is to just search for the item, I like using next for this because it's the closest equivalent to a find with a predicate in python, and it's lazy:

print(next((item for item in items if item.ident == "www"), None))

Gives:

<Item id=www sequence=1>

I would just throw it into a helper function:

def find_by_ident(items, ident):
    return next((item for item in items if item.ident == ident), None)

Also, if the SortedKeyList is encapsulated, you may also be able to maintain a simple dict along-side it where ident -> item if you wish to have O(1) complexity here as well, but it may be no big deal or not worth the extra memory/code complexity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM