简体   繁体   中英

Possibility to use operator.itemgetter in ternary operator as sort key

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM