【问题标题】:How to create a sorted representation of dictionary, using a custom comparator on tuple values?如何使用元组值的自定义比较器创建字典的排序表示?
【发布时间】:2017-05-14 14:40:34
【问题描述】:

我试图弄清楚如何使用 Python 3 中的值的自定义比较器,以一种通用的方式,创建具有值(元组)的字典的排序表示.

我已经阅读了这些主题,但我仍在苦苦挣扎:

Sort a Python dictionary by value

How to use a custom comparison function in Python 3?

作为一个具体示例,可以将我试图解决的问题视为“获取按总成本排序的产品列表,给定包含产品(键)的字典客户在他们的结帐中,以及每种产品的数量和成本(存储为 2 元组)。在 python 2 中,可以使用这样的东西:

checkout_dict = {'Apples': (1, 3), 'Oranges': (3, 3), 'Grapes': (7, 1),
                 'Cheese': (10, 1), 'Crackers': (4, 4)}


from operator import itemgetter


def sort_dict(dict, comparison_func):
    return sorted(dict.iteritems(), key=itemgetter(1),
                  cmp=comparison_func)


def cmp_total_cost(product_data_1, product_data_2):
    total_product_cost_1 = (product_data_1[0]) * (product_data_1[0])
    total_product_cost_2 = (product_data_2[0]) * (product_data_2[0])
    return total_product_cost_2 - total_product_cost_1


print sort_dict(checkout_dict, cmp_total_cost)

预期的输出如下所示:

[('Crackers', (4, 4)), ('Cheese', (10, 1)), ('Oranges', (3, 3)),
 ('Grapes', (7, 1)), ('Apples', (1, 3))]

但是,在 Python 3 中,sortedcmp 参数已被弃用,我们需要将其行为作为 key 参数的一部分。

我知道我们需要使用类似cmp_to_key function from the functools module 之类的东西,但我不知道如何才能将所有内容概括化。我对 itemgetter(1) 如何与 cmp_to_key 函数和自定义比较函数结合使用感到困惑。

另外,我知道通过上面的例子,我可以很容易地先遍历字典,计算总成本,然后进行排序,但我正在寻找一个通用的解决方案,我可以申请许多不同类型的比较。

注意

我也希望它尽可能高效。我发现了一些使用operator.itemgetter 可以真正帮助加快速度的信息: Sorting Dictionaries by Value in Python (improved?)

【问题讨论】:

  • 长话短说,sorted(checkout_dict, key=magic_function) 的预期输出是什么?
  • 在上面给出的示例中,它将是一个元组列表(product_name, (number_in_checkout, value)),由任何 magic_function 排序。
  • 但是按什么顺序呢?
  • 请发布您的预期输出
  • 感谢 DeepSpace 的帮助。魔术函数可能是 number_in_checkout 和 value 的乘积,也可能是它们的商,或者任何其他组合(例如 value^number_in_checkout)。我不是真的在处理篮子里的产品。

标签: python python-3.x sorting dictionary


【解决方案1】:

如果你只是想得到一个元组列表,按第一个元素乘以第二个元素排序,这样可以:

sorted(checkout_dict.items(), key=lambda item: item[1][0] * item[1][1])

#  [('Apples', (1, 3)), ('Grapes', (7, 1)), ('Oranges', (3, 3)), ('Cheese', (10, 1)),
#   ('Crackers', (4, 4))]

# or in the other way around
sorted(checkout_dict.items(), key=lambda item: item[1][0] * item[1][1], reverse=True)
# [('Crackers', (4, 4)), ('Cheese', (10, 1)), ('Oranges', (3, 3)), ('Grapes', (7, 1)), 
#  ('Apples', (1, 3))]

【讨论】:

  • 感谢 DeepSpace,我正在为任何使用元组元素值的 cmp 函数寻找一种通用方法,我可以将其指定为参数。也许我举的例子有点太具体了。这在 2.x 中似乎很容易,但在 3 中不确定!
  • @Jinglesting 老实说,我不确定我是否在这里看到了这个问题。无需从 cmp 函数返回 -1,0, 1(对于 ),您只需从 key 函数返回要比较的 实际 值。然后 Python 会计算出如何将该返回值与其他值进行比较。
  • 另外,lambda 函数的问题在于函数调用的所有开销(这也是我给出的 2.7 示例中的问题)。 “operator.itemgetter”有助于避免这些,但我不确定我是否可以根据我的要求利用这一点。你的解决方案可以用“itemgetter”来写吗?
  • 只需从 key 函数返回要比较的实际值。 我认为这并不总是那么容易。有时我需要比较像 (item2_val[0] * item1_val[1]) - (item1_val[0] * item2_val[1]) 这样的单独条目中的值,其中 items_val 是字典中条目的元组值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2013-06-28
相关资源
最近更新 更多