在Python中通过值对defaultdict进行排序

35

我有一个类似于这样的数据结构:

不同年份三个城市的人口如下。

Name  1990 2000 2010
A     10   20   30
B     20   30   10
C     30   10   20

我正在使用一个defaultdict来存储数据。

from collections import defaultdict
cityPopulation=defaultdict(list)
cityPopulation['A']=[10,20,30]
cityPopulation['B']=[20,30,10]
cityPopulation['C']=[30,10,20]
我想根据列表中的特定列(年份)对defaultdict进行排序。 例如,对1990年进行排序应该给出C,B,A,而对于2010年的排序则应该给出A,C,B
此外,这是存储数据的最佳方式吗?因为我要更改人口值,所以希望它是可变的。

嗯,你仍然很可能需要一个有序的数据结构。 - Silas Ray
我不希望数据结构被排序,因为顺序将取决于年份。 - imsc
@sr2222 没有,您可以使用“sorted()”来生成一个生成器。您不需要将这些值存储,因为它们会从“defaultdict”中被懒惰地生成。 - Gareth Latty
@Lattyware https://dev59.com/Em855IYBdhLWcg3wxHYq 请详细说明如何生成任何类型的排序算法,该算法可以与任何可能与效率松散相关的东西一起运行,而不必创建包含各种排序状态数据的对象? 从这个列表开始http://en.wikipedia.org/wiki/Sorting_algorithm,请告诉我哪些可以在不存储某种中间排序列表或对象的情况下工作。 - Silas Ray
@Lattyware,编程时想着“如果语言/库可以为我完成它,我就不需要知道发生了什么”并不是最好的想法。这种心态会导致低效的代码,而且往往会出现你无法修复的错误。 - Silas Ray
显示剩余7条评论
4个回答

43
>>> sorted(cityPopulation.iteritems(),key=lambda (k,v): v[0],reverse=True) #1990
[('C', [30, 10, 20]), ('B', [20, 30, 10]), ('A', [10, 20, 30])]
>>> sorted(cityPopulation.iteritems(),key=lambda (k,v): v[2],reverse=True) #2010
[('A', [10, 20, 30]), ('C', [30, 10, 20]), ('B', [20, 30, 10])]

注意,在Python 3中,您无法自动解包lambda参数,因此您需要更改代码。

sorted(cityPopulation.items(), key=lambda k_v: k_v[1][2], reverse=True) #2010

非常感谢。这非常接近我想要的。是否有一种方法可以按它们所代表的年份调用或命名列? - imsc
如果我有以上示例数据,我应该如何存储以实现此目的?在实际数据集中,列数(年份)的数量大约为100。谢谢。 - imsc
我不确定实现它的最佳方法。 - jamylak
我已经盯着Lambda几个月了,而你明显简单的例子终于帮助我理解了它们。谢谢! - JayCrossler

24
如果你想基于值而不是键进行排序,使用 data.items() 并使用 lambda kv: kv[1] 设置键,以便它选择值。

使用defaultdict的示例:

>>> from collections import defaultdict
>>> data = defaultdict(int)
>>> data['ciao'] = 17
>>> data['bye'] = 14
>>> data['hello'] = 23

>>> data
defaultdict(<type 'int'>, {'ciao': 17, 'bye': 14, 'hello': 23})

现在,让我们按值进行排序:
>>> sorted(data.items(), lambda kv: kv[1])
[('bye', 14), ('ciao', 17), ('hello', 23)]

如果您想让较大的数字先出现,请使用reverse=True

>>> sorted(data.items(), lambda kv: kv[1], reverse=True)
[('hello', 23), ('ciao', 17), ('bye', 14)]

请注意,key=lambda(k,v): v是一个更清晰(对我来说)的方式来表示key=lambda(v): v[1],只是后者是Python 3允许的唯一方式,因为lambda中的自动元组解包在Python 3中不可用
在Python 2中,你可以这样说:
>>> sorted(d.items(), key=lambda(k,v): v)
[('bye', 14), ('ciao', 17), ('hello', 23)]

1
类型错误:sorted期望1个参数,但得到了2个。需要添加key=。 - John Glen

12

defaultdict 不保持顺序。你可能需要使用一个 OrderedDict,或者每次将键排序为列表。

例如:

  from operator import itemgetter
  sorted_city_pop = OrderedDict(sorted(cityPopulation.items()))

编辑:如果你只想打印出顺序,直接使用内置的 sorted 函数:

for key, value in sorted(cityPopulation.items()):
    print(key, value)

1
我不想存储订单,只需要打印出来。 - imsc
如果您指的是额外的“key”参数,我刚刚将其删除了 - 鉴于元组首先按第一项排序并且键保证唯一,因此确实没有必要使用它。 - Gareth Latty
由于字典中的值是列表,我该如何按不同列进行排序? - imsc
1
sberry 的意思是你正在遮蔽内置的 sorted() 函数。sorted = OrderedDict(sorted(cityPopulation.items()) 这行代码只能运行一次。 - Sven Marnach
@imsc将lambda作为键参数传递给sorted方法,该方法将返回您想要从每个城市获取的列表项。 - Silas Ray
@SvenMarnach 没有注意到那个,已经修复。 - Gareth Latty

4
晚回答,不是对问题的直接回答,但如果您从谷歌搜索“在python中按值排序defaultdict”,来到这里,这就是我如何通过它的值(普通的python字典无法排序,但可以按排序后打印)来进行排序一个defaultdict
orders = {
    'cappuccino': 54,
    'latte': 56,
    'espresso': 72,
    'americano': 48,
    'cortado': 41
}

sort_orders = sorted(orders.items(), key=lambda x: x[1], reverse=True)

for i in sort_orders:
    print(i[0], i[1])

Demo


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接