Why is function appending the wrong value to list?

Viewed 120

I am creating a program that takes a dictionary with departments and who is in it, for example this dictionary here:

{"local": ["admin", "userA"],
 "public":  ["admin", "userB"],
 "administrator": ["admin"] }

And then returns a dictionary with all users as keys and a list of departments they are in as the value.

For example, the output for the previously given list is supposed to be:

{"admin" : ["local", "public", "administrator"],
 "userA" : ["local"],
 "userB" : ["public"]}

Here is my attempt:

def groups_per_user(group_dictionary):
    user_groups = {}
    # Go through group_dictionary
    
    user_groups["admin"] = []
    user_groups["userA"] = []
    user_groups["userB"] = []

    for x in group_dictionary.values():
        # Now go through the users in the group
        for user in x:
            if user in group_dictionary["local"]:
                user_groups[user].append("local")
            elif user in group_dictionary["public"]:
                user_groups[user].append("public")
            elif user in group_dictionary["administrator"]:
                user_groups[user].append("administrator")


            # Now add the group to the the list of
# groups for this user, creating the entry
# in the dictionary if necessary

    return(user_groups)

print(groups_per_user({"local": ["admin", "userA"],
        "public":  ["admin", "userB"],
        "administrator": ["admin"] }))

However, I am getting this output:

{'admin': ['local', 'local', 'local'],
 'userA': ['local'],
 'userB': ['public']}

In addition, I am defining the users in my function on lines 5-7 of my code. What am I supposed to do to make sure my code works for any given department and any given user?

For example, a user called "owner" and a department called "groupWorkspace" wouldn't work because I didn't define them in my code. Can someone explain how to fix this?

3 Answers

Using dict.setdefault we can do this quite easily:

groups = {"local": ["admin", "userA"],
          "public": ["admin", "userB"],
          "administrator": ["admin"]}

user_groups = {}
for group, users in groups.items():
    for user in users:
        user_groups.setdefault(user, []).append(group)

print(user_groups)

Output:

{'admin': ['local', 'public', 'administrator'],
 'userA': ['local'],
 'userB': ['public']}

A very bad approach, but I hope you will understand where you were wrong. admin is always in local so elif for public and administrator will never run

def groups_per_user(group_dictionary):
    user_groups = {}
    # Go through group_dictionary
    
    user_groups["admin"] = []
    user_groups["userA"] = []
    user_groups["userB"] = []

    for x in group_dictionary.values():
        # Now go through the users in the group
        for user in x:
            if user in group_dictionary["local"]:
                user_groups[user].append("local")
            if user in group_dictionary["public"]:
                user_groups[user].append("public")
            if user in group_dictionary["administrator"]:
                user_groups[user].append("administrator")
            
    for k,v in user_groups.items():
        user_groups[k] = list(set(v))


            # Now add the group to the the list of
# groups for this user, creating the entry
# in the dictionary if necessary

    return(user_groups)

print(groups_per_user({"local": ["admin", "userA"],
        "public":  ["admin", "userB"],
        "administrator": ["admin"] }))

#{'admin': ['administrator', 'local', 'public'], 'userA': ['local'], 'userB': ['public']}

Oneliner just for fun

d = {"local": ["admin", "userA"],
        "public":  ["admin", "userB"],
        "administrator": ["admin"] }

dict((k,[i[-1] for i in g]) for k, g in groupby(sorted(each_pair for k,v in d.items() for each_pair in sorted(map(lambda x: x[::-1], product([k],v)))), key=lambda x: x[0]))

I don't expect this to be the "Best" or most performant solution. I do however hope that the logic is clear and easy to follow.

*Please note: I am using terrible variable names on purpose. Hopefully nudging "anyone" to use it as an example or to understand the logic, and implement it ones self in your project. Making it less likely you will simply Copy+Paste without fully understanding or even editing this example *

The result of the following code is:

{ 'admin': ['local', 'public', 'administrator'], 
  'userA': ['local'], 
  'userB': ['public'] }

And finally the code to do the restructure, and potentially remove duplicates, in case your input data is not unique.

input = {
"local": ["admin", "userA"],
"public":  ["admin", "userB"],
"administrator": ["admin"]
}

def group_flip(input):
    # container for the result { user: [groups...], ...} structured result
    # this will be built up while iterating over the input
    user_groups = {}

    for g, us in input.items():
        # for each user in group
        for u in us:
            # we need to add it to the user_groups
            if not u in user_groups.keys():
                user_groups[u] = [g]
                continue
        
            # if not in list, add it
            if not g in user_groups[u]:
                user_groups[u].append(g)

    print(user_groups)
    return user_groups



if __name__ == '__main__':
    group_flip(input)
Related