Find minimum in dictionary of lists after Skyscanner request?

220 Views Asked by At

I am new to Python and I am playing around with Skyscanner's Python API to practice wth Python and APIs. A response from Skyscanner's API has the structure of a dictionary made up of multiple lists which are in turn made of many dictionaries.

See below: Skyscanner Query

result_base= flights_cache_service.get_cheapest_quotes(
market='AU',
currency='AUD',
locale='en-GB',
originplace='NYC',
destinationplace='MIA',
outbounddate='2017-07').parsed

The result_base variable is a dictionary:

[in]
result_base.keys()
[out]
[u'Quotes', u'Currencies', u'Places', u'Carriers']

and for example if I do:

[in]
print type(results_base['Quotes'])
[out]
list

Each item in the list is an itinerary that has multiple values such as:

[in]
result_base['Quotes'][0]
[out]
{u'Direct': False,
 u'MinPrice': 437.0,
 u'OutboundLeg': {u'CarrierIds': [843],
 u'DepartureDate': u'2017-07-01T00:00:00',
 u'DestinationId': 56628,
 u'OriginId': 67852},
 u'QuoteDateTime': u'2017-02-02T13:20:59',
 u'QuoteId': 1}

I am trying to find the most efficient way to find the minimum price out of the options given in the results_base['Quotes']. I tried looping through every item in the list but I am looking to see if there is a more efficient way to do it.

My code:

base_result={}
min_price=99999
for i in result_base['Quotes']:
    if i['MinPrice']<min_price:
        min_price=i['MinPrice']
        base_result['Direct']=i['Direct']
        base_result['MinPrice']=i['MinPrice']
        base_result['OutboundLeg']=i['OutboundLeg']
        base_result['QuoteDateTime']=i['QuoteDateTime'] 

Any help is appreciated, if you have any specific data structure that I can use, it is also welcome.

2

There are 2 best solutions below

2
On BEST ANSWER

As @ephemient points out,

you can skip a step in the previous version of this answer, and just jump straight to...

lowest_quote = min(result_base['Quotes'], key=lambda q: q['MinPrice'])

This will just grab the quote with the minimum price out of the sequence directly. (You can also use itemgetter('MinPrice') instead of the lambda by importing it from the operators library, for a slightly more optimized key function.)


Previous version:

quotes_and_prices = ((q['MinPrice'], q) for q in result_base['Quotes'])
min_price, quote = min(quotes_and_prices)

This uses a generator expression to generate a sequence of tuples, the first element of each tuple being the price, the second element of each tuple being the quote associated with that price.

It then grabs the smallest tuple out of the sequence, which due to how Python sorts tuples, is the one with the lowest price. Using sequence unpacking (described in the 'tuples' link above) it separates that back into two variables, min_price and quote.

Internally, this still involves looping through all of the prices, because that's a necessary condition for comparing them. However, it avoids repeatedly copying the individual fields of quotes around because it's just keeping a reference to each quote associated with its price as part of the tuple objects.

0
On

Pass the sort type and order in the querystring itself. Just one line and you will get the lowest price first. Set the pageSize to control the number of Itineraries you want.

querystring = {"sortType":"price","sortOrder":"asc","pageIndex":"0","pageSize":"10"}