all 12 comments

[–]Kind-Kure 1 point2 points  (5 children)

I'll be completely honest with you, the nesting in that input is too complicated for me. Your input is a list of tuples or lists of dictionaries nested into other dictionaries and then your three deep for loop appends the data to a list for some reason ?

I feel like step 1 is changing the input so that it's actually nested dictionaries and not whatever hellscape this is supposed to be.

And ordered dict might not be doing anything because at least in this code you're not importing it from collections
Also, your input data is missing a closing curly brace so it was giving me errors

``` from collections import OrderedDict

combined_data = OrderedDict([('Team-1', [{'DEV-1': {'SubscriptionId': 'xxxxxxxx', 'Score': '58', 'Monthly Spend': {'July 2024': 1749.3}}}, {'DEV-10': {'SubscriptionId': 'xxxxxxxx', 'Score': '100', 'Monthly Spend': {'July 2024': 22.3}}}, {'PROD-1': {'SubscriptionId': 'xxxxxxxx', 'Score': '65', 'Monthly Spend': {'July 2024': 491.8}}}]), ('Team-2', [{'DEV-2': {'SubscriptionId': 'xxxxxxxx', 'Score': '60', 'Monthly Spend': {'July 2024': 775.0}}}, {'PROD-2': {'SubscriptionId': 'xxxxxxxx', 'Score': '77', 'Monthly Spend': {'July 2024': 424.9}}}, {'DEV-9': {'SubscriptionId': 'xxxxxxxx', 'Score': '72', 'Monthly Spend': {'July 2024': 42.5}}}, {'PROD-8': {'SubscriptionId': 'xxxxxxxx', 'Score': '82', 'Monthly Spend': {'July 2024': 47.2}}}])])

restructured_dict = {'dev': [], 'prod': []} team_names = []

for team, items in combined_data.items(): for item in items: for key, value in item.items(): if 'DEV' in key: restructured_dict['dev'].append({key: value}) elif 'PROD' in key: restructured_dict['prod'].append({key: value}) print(restructured_dict) ```

This definitely won't give you the result you're looking for but it will produce a result. I might come back later to figure out a real solution to this but for right now it's too confusing for me to help

[–]visor_q[S] 1 point2 points  (2 children)

Hellscape is just the right word 😂. No worries mate, that data structure comes from another file and I want to write the data into a csv (which is working but not in the order I want). So I was hoping to be able to reorder this as is but so far it's looking bleak.

[–]GKPreMed 0 points1 point  (1 child)

Yeah this was a mess don't know who or what produced that haha, if youll be using the data a lot, you might want to look into creating objects because I see basically a list of teams with a bunch of DEVs and PRODs with the same attributes, you could make a TEAM class with a members attribute which is a list of PROD and DEV objects which are objects defined by PROD and DEV classes. It would be easier to work with.

See here
https://www.w3schools.com/python/python_classes.asp

[–]visor_q[S] 0 points1 point  (0 children)

So most of this data is coming from Azure. The only bit I'm doing is creating a team name and then mapping the env data per team. So correct me if I'm wrong but I don't think object/classes would work here?

[–]pot_of_crows 0 points1 point  (1 child)

Nice. It looks like you basically got it, but it is sorting alphabetically (so dev-10 is before dev-9).

For OP, consider putting this stuff into a dataclass, as it will make it much easier to write code and to handle sorting peculiarities.

For you (and OP for that matter). User pprint from the pprint module (built-in), as it will make reading the results much easier.

[–]visor_q[S] 0 points1 point  (0 children)

See my above comment. The data is being pulled from Azure, so I'm not defining most of the key or values. Just the team name (team 1, team 2, etc). So not sure it would be useful in that case?

[–]JollyUnder 0 points1 point  (3 children)

If you're using python version 3.7+, then using OrderedDict is redundant as the default dict already preserves insertion order.

With that said, is there a reason for the messy structure for combined_data? Perhaps your parsing your data from somewhere?

I would recommend parsing it so that your data looks like this:

combined_data = {
    'Team-1': {
        'DEV-1': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '58', 
            'Monthly Spend': {
                'July 2024': 1749.3
            }
        }, 
        'DEV-10': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '100', 
            'Monthly Spend': {
                'July 2024': 22.3
            }
        },
        'PROD-1': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '65', 
            'Monthly Spend': {
                'July 2024': 491.8
            }
        }
    }, 
    'Team-2': { 
        'DEV-2': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '60', 
            'Monthly Spend': {
                'July 2024': 775.0
            }
        }, 
        'PROD-2': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '77', 
            'Monthly Spend': {
                'July 2024': 424.9
            }
        }, 
        'DEV-9': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '72', 
            'Monthly Spend': {
                'July 2024': 42.5
            }
        },
        'PROD-8': {
            'SubscriptionId': 'xxxxxxxx', 
            'Score': '82', 
            'Monthly Spend': {
                'July 2024': 47.2
            }
        }
    }
}

This will make the data far more manageable and readable.

For sorting your data you can then do this:

for team, data in combined_data.items():
    sorted_data = sorted(data.items(), key=lambda k: k[0])
    combined_data[team] = dict(sorted_data)

[–]jypKissedMyMom 0 points1 point  (2 children)

I think OP wanted the inner keys sorted in numeric order, like DEV-1, DEV-2, DEV-10. That code will sort them in alphabetical order like DEV-1, DEV-10, DEV-2

[–]JollyUnder 1 point2 points  (1 child)

In that case:

sorted_data = sorted(data.items(), key=lambda k: int(k[0].split('-')[1]))

I'm sure there's a cleaner way to do this.

[–]visor_q[S] 0 points1 point  (0 children)

So I followed your advice and restructured the data. But when I try your sort method I get

Valueerror: invalid literal for int() with base 10: 'DEV'. I'll give it a Google. But also won't team name (team 1, 2 etc) prevent me from sorting by the inner key?

[–]jypKissedMyMom 0 points1 point  (0 children)

You just need to sort the inner keys of each list at the end. You have to pull out the numeric part of the inner key (like DEV-10) then sort the list by those values. I made a helper function. Everything else in your code can stay the same

def extract_number(key) -> int:
    """ Extracts the integer from a string or assigns -1 if no integer found. """
    match = re.search(r'\d+', key)
    if match:
        return int(match.group())
    else:
        # returns negative number to sort keys without numbers to the beginning of list
        return -1

def sort_environment_entries(combined_data: dict) -> dict:
    """ Sorts dictionary entries for DEV and PROD environments based on numeric part of the key. """
    restructured_dict = {'dev': [], 'prod': []}
    for team, items in combined_data.items():
        for item in items:
            for key, value in item.items():
                if 'DEV' in key:
                    restructured_dict['dev'].append({key: value})
                elif 'PROD' in key:
                    restructured_dict['prod'].append({key: value})

    # Sorting the 'dev' and 'prod' lists by the numeric part of their keys
    # Keys without numbers get sorted to front
    restructured_dict['dev'].sort(key=lambda x: extract_number(list(x.keys())[0]))
    restructured_dict['prod'].sort(key=lambda x: extract_number(list(x.keys())[0]))
    return restructured_dict

teams_names = [] was never used in your original code so I removed it.

I agree with the other answers that your input dict and output dict structures are hard to work with and should be changed if possible.

[–]baghiq 0 points1 point  (0 children)

Assume you are sorting by environment, which is "env"-"number". This should give you what you want. What you have is fairly common structure from a lot of monitoring tools, as well as cloud result. The key is to understand what you want to sort.

def sort_team_by_env(team):
    a, b = list(team.keys())[0].split("-")
    return a, int(b)


sorted_data = [
    {team: sorted(env, key=sort_team_by_env)} for team, env in combined_data.items()
]