I have a list of tuples that I'm trying to sort. The tuples contain strings:
connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
The strings in the tuples have numeric values stored in a dict:
valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
What I'd like to do is sort the list by the sum of the values in the dict for the tuples. Desired output for this toy example would be:
[(C,D), (A,C), (C,B), (D,B)]
which would have the sums of:
[3, 4, 6, 7]
Using itemgetter, I can sort alphabetically by position:
sortedView = sorted(connectionsList, key=itemgetter(0,1))
However, I'm having trouble looking up the values from itemgetter in the dict. Running this:
sortedView = sorted(connectionsList, key=valuesDict[itemgetter(0)] + valuesDict[itemgetter(1)])
gives a dict error of KeyError: operator.itemgetter(0).
How do I create a sort based on the values in the dict?
解决方案
Don't use itemgetter instances; you need to call them but they are overkill here.
Just access the dictionary directly with the key values passed into a lambda. It is a tuple, so add indexing:
sortedView = sorted(connectionsList, key=lambda k: valuesDict[k[0]] + valuesDict[k[1]])
The key argument must be a callable object, that takes a single argument (one of the items being sorted), and returns the value you are actually sorting on. itemgetter() that returns results based on indexing on the object you call it with; itemgetter(0)(some_tuple) would return the first element from the tuple passed in.
A lambda can do the same, in the above solution the lambda returns your desired sum for the given tuple.
Demo:
>>> connectionsList = [('C', 'B'), ('A', 'C'), ('D', 'B'), ('C','D')]
>>> valuesDict = {'A':3, 'B':5, 'C':1, 'D':2}
>>> sorted(connectionsList, key=lambda k: valuesDict[k[0]] + valuesDict[k[1]])
[('C', 'D'), ('A', 'C'), ('C', 'B'), ('D', 'B')]
You could also treat your tuple as an arbitrary-length sequence. If you then also account for the possibility that not all values in the tuples are valid keys for the valuesDict mapping (taking 0 instead), you could also get your solution with:
sortedView = sorted(connectionsList, key=lambda k: sum(valuesDict.get(v, 0) for v in k))
This is more general and robust.
You didn't need to use an itemgetter() object in your alphabetical sort either; the tuples are already provided in 0, 1 order, so you'd get the same sorting order without using a sort key.