我怎样才能对一个复杂的字典关键字进行排序

2024-10-05 14:28:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我处理了这些非常复杂的数据文件,在处理每个文件时,我使用orderedDictionary来捕获键和值。每个orderedDictionary都会附加到一个列表中,所以我的最终结果是一个字典列表。由于这些文件中捕获的数据的多样性,它们有许多共同的键,但是有足够多的不常见的键使得将数据导出到Excel比我希望的要复杂,因为我确实需要以一致的结构推出数据。在

每个键的结构如下

Q_#_SUB_A_COLUMN_#_NUMB_#

例如我有

^{pr2}$

我们可以把这个键翻译如下

 Question 123
 SubItem D
 Column C
 Instance 17

因为有子项D、列C和实例17,所以必须有子项a、列B和实例16

但是,其中一个源文件可能填充了数据值(以及上一个示例中的键以及其他源文件可能以

Q_123_SUB_D_COLUMN_C_NUMB_13

因此,当我遍历字典列表以获取所有唯一键实例时,我可以在中使用它们csv.dictwriter作为列标题,我的计划是对结果列表中唯一的列标题进行排序,但我似乎不能使排序工作

特别是我需要它来排序,这样结果看起来像

 Q_122_SUB_A_COLUMN_C_NUMB_1
 Q_122_SUB_B_COLUMN_C_NUMB_1
 Q_123_SUB_A_COLUMN_C_NUMB_1
 Q_123_SUB_B_COLUMN_C_NUMB_1
 Q_123_SUB_C_COLUMN_C_NUMB_1
 Q_123_SUB_D_COLUMN_C_NUMB_1
 dot
 dot
 dot
 Q_123_SUB_A_COLUMN_C_NUMB_17
 Q_123_SUB_B_COLUMN_C_NUMB_17
 Q_123_SUB_C_COLUMN_C_NUMB_17
 Q_123_SUB_D_COLUMN_C_NUMB_17

最大的问题是,在我打开这些文件的任何特定集合之前,我不知道有多少问题被回答,有多少子问题被回答,有多少列与每个问题或子问题相关联,或者有多少个特定的问题、子问题或列组合的实例,我不想知道。使用Python,我可以将超过1200行的SAS代码减少到95行,但在我开始将其写入CSV文件之前,我似乎无法理解。在

如有任何意见,将不胜感激。在

我的计划是通过遍历字典列表找到所有唯一的键,然后对这些键进行正确排序,这样我就可以使用这些键作为列标题创建一个csv文件。我知道我可以找到唯一的键,把它推出来,手动排序,然后把排序后的文件读回,但这看起来很笨拙。在


Tags: 文件数据实例标题列表字典排序column
3条回答

只需提供一个足够聪明的函数作为排序时的键。在

>>> (lambda x: tuple(y(z) for (y, z) 
                     in zip((int, str, str, int), 
                            x.split('_')[1::2])))('Q_122_SUB_A_COLUMN_C_NUMB_1')
(122, 'A', 'C', 1)

您可以使用正则表达式来提取键的不同部分,并使用这些部分进行排序。在

例如

import re

names = '''Q_122_SUB_A_COLUMN_C_NUMB_1
Q_122_SUB_B_COLUMN_C_NUMB_1
Q_123_SUB_B_COLUMN_C_NUMB_1
Q_123_SUB_A_COLUMN_C_NUMB_17
Q_123_SUB_D_COLUMN_C_NUMB_1
Q_123_SUB_B_COLUMN_C_NUMB_17
Q_123_SUB_C_COLUMN_C_NUMB_1
Q_123_SUB_C_COLUMN_C_NUMB_17
Q_123_SUB_A_COLUMN_C_NUMB_1
Q_123_SUB_D_COLUMN_C_NUMB_17'''.split()

def key(name, match=re.compile(r'Q_(\d+)_SUB_(\w+)_COLUMN_(\w+)_NUMB_(\d+)').match):
    # not sure what the actual order is, adjust the priorities accordingly
    return tuple(f(value) for f, value in zip((str, int, int, str), match(name).group(3, 4, 1, 2)))

for name in names:
    print name

names.sort(key=key)

print

for name in names:
    print name

为了解释密钥提取过程,我们知道密钥具有一定的模式。正则表达式在这里非常有用。在

^{pr2}$

在正则表达式中,用parens包装的字符串部分是组。\d表示任何十进制数字。+表示应该有一个或多个前一个字符。所以\d+表示一个或多个十进制数字。\w对应一个字母。在

如果字符串与此模式匹配,我们可以使用group方法轻松访问该字符串中的每个分组。您可以访问多个组,只需包含更多组号

例如

m = match('Q_122_SUB_B_COLUMN_C_NUMB_1')
# m.group(1) == '122'
# m.group(2) == 'B'
# m.group(3, 4) == ('C', '1')

这与Ignacio的方法类似,只是在模式上更加严格。一旦你能把你的头脑围绕在这一点上,为排序创建适当的键应该很简单。在

假设键包含在一个列表中,比如keyList

list_to_sort=[]

for key in keyList:
    sortKeys=key.split('_')
    keyTuple=(sortKeys[1],sortKeys[-1],sortKeys[3],sortKeys[5],key)
    list_to_sort.append(keyTuple)

在这之后,列表中的项是如下的元组

^{pr2}$

我不确定itemgetter到底是做什么的,但这是可行的,看起来更简单,但没有其他两个解决方案优雅。在

请注意,我在tuple中排列键的顺序与键的实际显示方式不同。我没必要这么做

for key in keyList:
    sortKeys=key.split('_')
    keyTuple=(sortKeys[1],sortKeys[3],sortKeys[5],sortKeys[7],key)
    list_to_sort.append(keyTuple)

然后就这样做了

list_to_sort.sort(key=itemgetter(0,3,1,2)

对我来说追踪第一个更容易

相关问题 更多 >