【问题标题】:Sorting a dictionary by a split key通过拆分键对字典进行排序
【发布时间】:2015-08-05 20:11:25
【问题描述】:

好的,所以我有一个包含字符串中字符位置的字典,但是,我在字典中有单独的字符串,这使它看起来像这样:

{
'24-35': 'another word',
'10-16': 'content',
'17': '[',
'22': ']',
'23': '{',
'37': ')',
'0-8': 'beginning',
'36': '}',
'18-21': 'word',
'9': '(',
}

我正在尝试按键对该数组进行排序,使其看起来像这样

{
'0-8': 'beginning',
'9': '(',
'10-16': 'content',
'17': '[',
'18-21': 'word',
'22': ']',
'23': '{',
'24-35': 'another word',
'36': '}',
'37': ')'
}

字典是由foreaching通过这个字符串构建的:
'beginning(content[word]{another word})',并在括号处拆分。

我正在尝试使用@Briananswerthis question 对字典进行排序,但是,它按字母顺序排序(因为它们已被转换为字符串)在测距过程中(让它说'0-8'的东西)。

我的问题是:

我该如何转换:

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"

更具体地说:将key 排序为int(key.split('-')[0]),但仍保留输出范围?

【问题讨论】:

  • 只是好奇:为什么不构建字符串同时(甚至不)构建字典?
  • @StefanPochmann,我确实在构建数组时构建了字符串,对于每个字符,如果它不是括号,它就会被添加到变量中,一旦括号进入,或者字符串结束,字符串被推送到字典。
  • @Quill 我会说,您根本不必存储范围,只需存储起始索引。您总是可以通过将字符串的长度添加到起始索引来找到结束索引。
  • @Quill 我不是指最终成为您的字典键的字符串部分。我的意思是您要在此处构建的大字符串。代表整个字典的那个。为什么要按顺序解析这些部分,将它们存储在它们无序的字典中,然后将它们从字典中取出,这样你就必须重新排序它们?为什么不按原始顺序取出零件并直接构建大的最终字符串?
  • 欢迎关注my code on Code Review

标签: python sorting dictionary


【解决方案1】:

使用sorted 的键函数将值转换为int。它看起来像:

sorted(d.items(), key=lambda v: int(v[0].split("-")[0]))

此逻辑仅用于排序; sorted 返回的项目仍将使用范围表示法。

【讨论】:

  • 嗨,这对我很有帮助。但是,有没有一种方法可以解释密钥的两个部分,例如我们的密钥为 8-9,8-4,4-9。理想情况下,它们不仅按第一个数字排序,而且按两者排序,例如:4-9,8-4,8-​​9。
  • @NJD 当然,只需使用复杂的排序键。 sorted(d.items(), key=lambda v: tuple(int(e) for e in v.split("-")))
【解决方案2】:

您可以将字典转换为元组列表(键值对),然后根据键中的第二个数字(如果连字符)对其进行排序。

>>> data = {'24-35': 'another word', '10-16': 'content', '17':
...         '[', '22': ']', '23': '{', '37': ')', '0-8': 'beginning', '36': '}',
...         '18-21': 'word', '9': '('}
>>> from pprint import pprint
>>> pprint(sorted(data.items(),
...     key=lambda x: int(x[0].split("-")[1] if "-" in x[0] else x[0])))

[('0-8', 'beginning'),
 ('9', '('),
 ('10-16', 'content'),
 ('17', '['),
 ('18-21', 'word'),
 ('22', ']'),
 ('23', '{'),
 ('24-35', 'another word'),
 ('36', '}'),
 ('37', ')')]

这里,关键部分是lambda x: int(x[0].split("-")[1] if "-" in x[0] else x[0])。我们检查- 是否在x[0] 中,如果存在,则基于- 进行拆分,并获取索引1 处的元素,基本上是- 之后的数字。如果密钥没有-,则将字符串原样转换为int


如果你想保持字典本身的项目顺序,那么你可以使用collections.OrderedDict,像这样

>>> from collections import OrderedDict
>>> d = OrderedDict(sorted(data.items(),
...         key=lambda x: int(x[0].split("-")[1] if "-" in x[0] else x[0])))
>>> for key, value in d.items():
...     print(key, value)
...     
... 
0-8 beginning
9 (
10-16 content
17 [
18-21 word
22 ]
23 {
24-35 another word
36 }
37 )

【讨论】:

  • "a".split("-") 返回["a"] 并且在这里对第一个值而不是第二个值进行排序应该同样有效,因为所有范围都是互斥的,不是吗?
  • 是否也可以完成将结果转换为字典?
  • @jwilner 是的,你是对的。但如果没有必要,我会尽量避免使用split。而且,这很容易理解,对吧? ;-)
  • @thefourtheye 或者你可以使用splitcount=1partition,如果你愿意的话。
  • 我倾向于认为更少的条件句 == 更清晰,但每个人都有自己的想法!
【解决方案3】:
>>> d = {
'24-35': 'another word',
'10-16': 'content',
'17': '[',
'22': ']',
'23': '{',
'37': ')',
'0-8': 'beginning',
'36': '}',
'18-21': 'word',
'9': '(',
}
>>> pprint(sorted(d.items(), key=lambda x: int(x[0].partition('-')[0])))
[('0-8', 'beginning'),
 ('9', '('),
 ('10-16', 'content'),
 ('17', '['),
 ('18-21', 'word'),
 ('22', ']'),
 ('23', '{'),
 ('24-35', 'another word'),
 ('36', '}'),
 ('37', ')')]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2015-03-31
    • 1970-01-01
    • 2020-10-27
    • 2011-12-11
    • 2014-04-13
    • 1970-01-01
    相关资源
    最近更新 更多