There is a list of dictionaries of the same type - items
. I want to get a unified dictionary containing as a key the name of the sorting described in the mappings
and a list of titles of these dictionaries sorted by the field I need. The dictionaries and mapping themselves contain more fields and described sorts (see the code below).
from operator import itemgetter
items = [
{'title': 'C Item', 'something': 1.5, 'one': 2, 'two': 3},
{'title': 'B Item', 'something': 1.0, 'one': 1, 'two': None},
{'title': 'D Item', 'something': 1.5, 'one': 4, 'two': None},
{'title': 'A Item', 'something': 2.0, 'one': 3, 'two': 2},
]
mappings = {
'title-desc': {'key': lambda: itemgetter('title'), 'reverse': True},
'smth-asc': {'key': lambda: itemgetter('something'), 'reverse': False},
# ... Other ways to sort by other fields ...
'one/two-asc': {'key': lambda: ???, 'reverse': False}, # Questions goes here, comment this line
}
results = {}
for key, value in mappings.items():
sorted_items = sorted(items, key=value['key'](), reverse=value['reverse'])
sorted_values = {key: [item['title'] for item in sorted_items]}
results.update(sorted_values)
print(results)
Everything works as expected and this output is displayed:
{
'title-desc': ['D Item', 'C Item', 'B Item', 'A Item'],
'smth-asc': ['B Item', 'C Item', 'D Item', 'A Item']
}
But I faced such a challenge. The dictionary contains 2 fields - one
and two
. Field one
is always filled, and field two
is optional. Is it possible to describe the logic using the ternary operator and itemgetter: If field two
contains data, use it otherwise use field one
? Something like this: ??? = itemgetter('two') if itemgetter('two') else itemgetter('one')
??? = itemgetter('two') if itemgetter('two') else itemgetter('one')
, but it won't work. I expect this output:
{
'title-desc': [...],
'smth-asc': [...],
'one/two-asc': ['B Item', 'A Item', 'C Item', 'D Item']
}
Or what other solutions could there be?
Thanks in advance.
It's possible if you don't use the itemgetter
for the condition:
# if the empty 'two' fields are filled with None
lambda x: x["two"] if x["two"] is not None else x["one"]
# if the 'two' key isn't in the dict instead of being filled with None:
lambda x: x["two"] if "two" in x else x["one"]
I didn't use if x["two"]
as a condition, because it would return False
if x["two"]
is 0
, too.
Also, the use of lambda
for your itemgetter functions is not necessary, instead, do:
'smth-asc': {'key': itemgetter('something'), 'reverse': False},
'one/two-asc': {'key': lambda x: x["two"] if x["two"] is not None else x["one"], 'reverse': False}
Then, use these functions directly as the sort key, without calling them: key=value['key']
You could define your own "ternary" itemgetter
-like function that returns a callable that does what you want:
from operator import itemgetter
from pprint import pprint
def ternary_itemgetter(a, b):
return lambda obj: obj[b] if obj[b] is not None else obj[a]
items = [
{'title': 'C Item', 'something': 1.5, 'one': 2, 'two': 3},
{'title': 'B Item', 'something': 1.0, 'one': 1, 'two': None},
{'title': 'D Item', 'something': 1.5, 'one': 4, 'two': None},
{'title': 'A Item', 'something': 2.0, 'one': 3, 'two': 2},
]
mappings = {
'title-desc': {'key': lambda: itemgetter('title'), 'reverse': True},
'smth-asc': {'key': lambda: itemgetter('something'), 'reverse': False},
# ... Other ways to sort by other fields ...
'one/two-asc': {'key': lambda: ternary_itemgetter('one', 'two'), 'reverse': False},
}
results = {}
for key, value in mappings.items():
sorted_items = sorted(items, key=value['key'](), reverse=value['reverse'])
sorted_values = {key: [item['title'] for item in sorted_items]}
results.update(sorted_values)
pprint(results, sort_dicts=False)
Output:
{'title-desc': ['D Item', 'C Item', 'B Item', 'A Item'],
'smth-asc': ['B Item', 'C Item', 'D Item', 'A Item'],
'one/two-asc': ['B Item', 'A Item', 'C Item', 'D Item']}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.