Reputation: 15
I am starting with a list of orders, each order has a price and a timestamp amongst other things. The list starts off empty, and I can amend, remove and insert into the list.
The list needs to always remain sorted based on price and then timestamp, so orders of the same price will be given priority based on the time they were received.
I am just trying to find a more efficient way to do this
my_list.append(order)
my_list.sort(key=lambda k: (k.price, k.timestamp))
I was looking at bisect but it doesn't seem to be able to do this on a key. I'm trying to keep my_list sorted as efficiently as possible
Upvotes: 1
Views: 333
Reputation: 382
Edit: better use next to get to the index
Maybe this does the trick: look for the first item greater than you want to insert, get the index, and use it for the insert:
def insert_val(lst, val):
try:
index = next( i for i, x in enumerate(lst)
if (x.price, x.timestamp) > (val.price, val.timestamp))
except StopIteration: # greater item not found
lst.append(val)
else:
lst.insert(index, val) # insert val on the index of the found item
Upvotes: 0
Reputation: 106768
An easy approach to sorting objects by a key without using a key function is to sort the objects by a tuple order, where each tuple consists of all the relevant keys and the object itself:
import bisect
from collections import namedtuple
Order = namedtuple('Order', ('item', 'price', 'timestamp'))
orders = [
Order('banana', 2, 5),
Order('apple', 4, 3),
Order('orange', 2, 4),
Order('mango', 1, 7),
Order('guava', 3, 1)
]
my_list = []
for count, order in enumerate(orders, 1):
print(f'Insertion #{count}')
bisect.insort_right(my_list, (order.price, order.timestamp, order))
for _, _, order in my_list:
print(order)
print()
This outputs:
Insertion #1
Order(item='banana', price=2, timestamp=5)
Insertion #2
Order(item='banana', price=2, timestamp=5)
Order(item='apple', price=4, timestamp=3)
Insertion #3
Order(item='orange', price=2, timestamp=4)
Order(item='banana', price=2, timestamp=5)
Order(item='apple', price=4, timestamp=3)
Insertion #4
Order(item='mango', price=1, timestamp=7)
Order(item='orange', price=2, timestamp=4)
Order(item='banana', price=2, timestamp=5)
Order(item='apple', price=4, timestamp=3)
Insertion #5
Order(item='mango', price=1, timestamp=7)
Order(item='orange', price=2, timestamp=4)
Order(item='banana', price=2, timestamp=5)
Order(item='guava', price=3, timestamp=1)
Order(item='apple', price=4, timestamp=3)
So that each insertion takes only an average time complexity of O(n) as opposed to O(n log n) if you had used the sort
method.
Upvotes: 1