onlyjoshn
onlyjoshn

Reputation: 21

question about custom sorting using key argument in sorted()

I'm trying to gain some insight in to why I'm receiving an error message.

I'm trying to sort a dictionary using a custom function. I realize I can use lambda to achieve the same goal, as well as sorting the dictionary in to tuples first, but what I'm really trying to do is understand why my function isn't returning a list.

sample_dict = {"a":4,"b":2,"c":7,"d":9}

def all_values(x):
    return list(x.values())

print(sorted(sample_dict, key = all_values))

Expecting for return list(x.values()) to return a list to be used in the sorted key argument, but instead, I'm given the error message:

AttributeError: 'str' object has no attribute 'values'

Upvotes: 2

Views: 96

Answers (2)

Lante Dellarovere
Lante Dellarovere

Reputation: 1858

I think you've been confused by the way key argument works.
Essentially, it maps a given function over all elements of your iterable, and then sorted sorts based on the outputs of the mapping.
In fact, when you sort sample_dict, you are sorting its keys, which are strings:

sample_dict = {"b":2, "c":7, "d":9, "a":4}
print(sorted(sample_dict))
# ['a', 'b', 'c', 'd']

and if I try to map all_values to this list of strings:

list(map(all_values, sample_dict))

# AttributeError: 'str' object has no attribute 'values'

all_values must get a string in input then, like @Jean-FrançoisFabre suggests:

def all_values(x):
    return sample_dict[x]

print(sorted(sample_dict, key = all_values))
# ['b', 'a', 'c', 'd']

Upvotes: 0

Jean-François Fabre
Jean-François Fabre

Reputation: 140168

you mean to sort the keys according to the values.

The key function is meant to convert the dictionary key to something comparable (if you omit it, it's like passing an identity function, you're comparing on the dictionary key itself). You want to return the value from the key, so it's a dictionary access:

sample_dict = {"a":4,"b":2,"c":7,"d":9}

def all_values(x):
    return sample_dict[x]

print(sorted(sample_dict, key = all_values))

You were expecting the dictionary to be passed in the key, which would have no interest at all. key must be different at each call sort does.

Using a lambda is of course shorter

print(sorted(sample_dict, key = lambda x: sample_dict[x]))

but passing a real function allows to insert side effects more easily:

def all_values(x):
    print("key input",x)
    return sample_dict[x]

with that you get an insight of what sort is doing (and the final result is printed by the main print statement):

key input b
key input a
key input c
key input d
['b', 'a', 'c', 'd']

and now you understand why list('b'.values()) failed.

Upvotes: 3

Related Questions