gtopal
gtopal

Reputation: 594

How to sort a dictionary inside a dictionary based on the key(alphabetically) of the inner dictionary in python

Despite the fact that I have seen a lot of answers about sorting a dictionary of a dictionary I was not able to adjust the solution to my problem.

Here is the structure of my dictionary:

OrderedDict([('2018-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 8}), ('2017-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 804,'ALFAMINO 400 GR.': 4, 'Forticare Orange/Lemon 4 X125ml': 15})])

The outer dictionary has as key a date in format year-month The outer dictionary has as value a dictionary in format {'name of product: quantity}

The inner dictionary has as key the name of the product The inner dictionary has as value the quantity(of the product)

My aim is to sort my outer dictionary based on the latest date(the newest to be first) and my inner dictionary based on the name of the product alphabetically.

In other words:

OrderedDict([('2018-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 8}),('2017-11',{'ALFAMINO 400 GR.': 4,'Forticare Orange/Lemon 4 X125ml': 15,'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 804})])

First goes the date 2018-11, is "newest" than 2017-11 and in inner dictionaries if I have more than one records as the dictionary with key 2017-11, first goes the ALFAMINO (starts with A), then the Forticare (starts with F) and so on..

Here is my code:

def warehouse_pending_products(request):
    template_name= 'warehouse/warehouse_pending_products.html'
    pendingOrdersResult={}
    pendingOrdersList=Order.objects.filter(finished=0)
    for order in pendingOrdersList:
        orderYear=order.invoice_date.year
        orderMonth=order.invoice_date.month
        orderDate=str(orderYear)+'-'+str(orderMonth)

        orderProductsWithoutSerials=ProductSerialNumbers.objects.filter(snumber__isnull=True).filter(order=order.id)#order_by('product__name')
        if orderDate in pendingOrdersResult:
            for op in orderProductsWithoutSerials:
                p_name=op.product.name.encode("utf-8")
                if p_name in pendingOrdersResult[orderDate]:


                    pendingOrdersResult[orderDate][p_name]+=1 
                else:

                    pendingOrdersResult[orderDate][p_name]=1
        else:
            if orderProductsWithoutSerials:
                pendingOrdersResult[orderDate]={}
                for op in orderProductsWithoutSerials:
                    p_name=op.product.name.encode("utf-8")
                    if p_name in pendingOrdersResult[orderDate]:
                        pendingOrdersResult[orderDate][p_name]+=1
                    else:
                        pendingOrdersResult[orderDate][p_name]=1


    result = collections.OrderedDict(sorted(pendingOrdersResult.iteritems(), key=lambda (k, v): (pendingOrdersResult[k])))

My dictionary is the pendingOrdersResult.

The result = collections.OrderedDict(sorted(pendingOrdersResult.iteritems(), key=lambda (k, v): (pendingOrdersResult[k]))) gives wrong result.

enter image description here

Upvotes: 0

Views: 107

Answers (2)

Christian B.
Christian B.

Reputation: 824

Try the following (tested with python 3.7.1):

import collections

raw    = dict([('2018-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 8}), ('2017-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 804,'ALFAMINO 400 GR.': 4, 'Forticare Orange/Lemon 4 X125ml': 15})])
data   = {key : collections.OrderedDict(sorted(value.items(), key=lambda entry: entry[0])) for key, value in raw.items()}
result = collections.OrderedDict(sorted(data.items(), key = lambda entry: entry[0]))


print(result)

EDIT: with a function to avoid the "c&p" code:

import collections

def sort_dict(unsorted):
    return collections.OrderedDict(sorted(unsorted.items(), key=lambda entry: entry[0]))

raw    = dict([('2018-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 8}), ('2017-11', {'NEOCATE JUNIOR  WITHOUT FLAVOUR 400 gr.': 804,'ALFAMINO 400 GR.': 4, 'Forticare Orange/Lemon 4 X125ml': 15})])
result = sort_dict({key : sort_dict(value) for key, value in raw.items()})

print(result)

Upvotes: 1

D Malan
D Malan

Reputation: 11484

It sounds like you need to call the sorted function on each of the "inner" dictionaries individually, as well as on the "outer" dictionary. You would also need to cast your inner dictionaries to have the OrderedDict type for them to be sortable. Here's what I could come up with, but there might be shorter/more idiomatic ways to do this:

# Sort the outer dictionary by key from high to low
OrderedDict(sorted(d.items(), key=lambda t: t[0], reverse=True))

# Sort the inner dictionaries by key
for item in d.items(): 
    d[item[0]] = OrderedDict(sorted(item[1].items(), key=lambda x: x[0])) 

Upvotes: 2

Related Questions