【问题标题】:Sort a dictionary with custom sorting function使用自定义排序功能对字典进行排序
【发布时间】:2015-11-01 09:09:39
【问题描述】:

我使用json.load(data_file)从文件中读取了一些 JSON 数据

 {
  "unused_account":{
    "logins": 0,
    "date_added": 150
  },
  "unused_account2":{
    "logins": 0,
    "date_added": 100
  },
  "power_user_2": {
    "logins": 500,
    "date_added": 400,
    "date_used": 500
  },
  "power_user": {
    "logins": 500,
    "date_added": 300,
    "date_used": 400
  },
  "regular_user": {
    "logins": 20,
    "date_added": 200,
    "date_used": 300
  }
}

我想按特定顺序对条目进行排序。我找到了很多按键或单个值排序的示例。但我想按以下规则对值进行排序:

  1. groupby 登录次数递减,但登录次数为 0 的用户在前
  2. 按添加日期对登录次数为 0 的用户进行排序
  3. 按使用日期对至少有 1 次登录的用户进行排序

理想情况下,我会像这样编写自己的比较函数:

def compare(elem1, elem2):
    """Return >0 if elem2 is greater than elem1
        <0 if elem2 is lesser than elem1
        0 if they are equal"""
    #rule 1 group by logins
    if elem1['logins'] != elem2['logins']:
        if elem1['logins'] == 0:
            return -1
        if elem2['logins'] == 0:
            return 1
        return elem2['logins'] - elem1['logins']
    # rule 2 sort on date_added
    if elem1['logins'] == 0 and elem2['logins'] == 0:
        return elem2['date_added'] - elem1['date_added']
    #rule 3 sort on date_used
    if elem1['logins'] == elem2['logins'] and elem1['loigns'] > 0:
        return elem2['date_used'] - elem1['date_used']
    return 0  # default

我不知道在哪里以及如何插入我的排序功能。

【问题讨论】:

  • 你能给我们一个预期的输出吗?所以你首先要 0 次登录(按添加日期在哪个方向排序?然后其余的按使用日期登录,再次,哪个方向?
  • 啊,不,你要先0次登录,然后降序登录,在一个登录次数相同的组内,是日期排序,降序。跨度>
  • 字典是无序的数据类型,您可能需要查看集合模块中的OrderedDict

标签: python json python-2.7 sorting dictionary


【解决方案1】:

我假设您知道字典是无序的,并且您想要对值或键值对进行排序。以下示例对值进行排序。

如果你修正了最后一个if 中的loigns 错字,你的比较功能已经可以工作了:

>>> sorted(sample.itervalues(), cmp=compare))
[{'logins': 0, 'date_added': 150}, {'logins': 0, 'date_added': 100}, {'logins': 500, 'date_added': 400, 'date_used': 500}, {'logins': 500, 'date_added': 300, 'date_used': 400}, {'logins': 20, 'date_added': 200, 'date_used': 300}]
>>> pprint(_)
[{'date_added': 150, 'logins': 0},
 {'date_added': 100, 'logins': 0},
 {'date_added': 400, 'date_used': 500, 'logins': 500},
 {'date_added': 300, 'date_used': 400, 'logins': 500},
 {'date_added': 200, 'date_used': 300, 'logins': 20}]

不过,您也可以使用以下排序键:

(not d['logins'], d['logins'], d['date_used'] if d['logins'] else d['date_added'])

这将创建一个 (has_logins, num_logins, date) 元组,其中选择的日期基于用户是否已登录。

将其用作sorted() 函数的key 参数,并反转排序,如下所示:

>>> key = lambda d: (not d['logins'], d['logins'], d['date_used'] if d['logins'] else d['date_added'])
>>> pprint(sorted(sample.itervalues(), key=key, reverse=True))
[{'date_added': 150, 'logins': 0},
 {'date_added': 100, 'logins': 0},
 {'date_added': 400, 'date_used': 500, 'logins': 500},
 {'date_added': 300, 'date_used': 400, 'logins': 500},
 {'date_added': 200, 'date_used': 300, 'logins': 20}]

如果您还需要密钥,请使用 dict.iteritems() 并更新密钥函数以接受 (k, d) 元组:

>>> key = lambda (k, d): (not d['logins'], d['logins'], d['date_used'] if d['logins'] else d['date_added'])
>>> pprint(sorted(sample.iteritems(), key=key, reverse=True))
[('unused_account', {'date_added': 150, 'logins': 0}),
 ('unused_account2', {'date_added': 100, 'logins': 0}),
 ('power_user_2', {'date_added': 400, 'date_used': 500, 'logins': 500}),
 ('power_user', {'date_added': 300, 'date_used': 400, 'logins': 500}),
 ('regular_user', {'date_added': 200, 'date_used': 300, 'logins': 20})]

【讨论】:

  • 谢谢,事实上我也需要钥匙。感谢您提供该 sn-p。
猜你喜欢
  • 2018-08-26
  • 2014-02-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多