我已经处理了这些非常复杂的数据文件,并且在处理每个文件时,我使用了orderedDictionary来捕获键和值。每个orderedDictionary都附加到一个列表,所以我的最终结果是一个字典列表。由于这些文件中捕获的数据的多样性,它们有许多共同的键,但是有足够的不常见键将数据导出到Excel比我希望的更复杂,因为我真的需要以一致的方式推出数据结构
每个键都具有类似
的结构Q_#_SUB_A_COLUMN_#_NUMB_#
所以例如我有
Q_123_SUB_D_COLUMN_C_NUMB_17
我们可以按如下方式翻译密钥
Question 123
SubItem D
Column C
Instance 17
因为存在SubItem D,C列和实例17,所以必须有SubItemA,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我能够将超过1,200行的SAS代码减少到95,但在我开始将其写入CSV文件之前,这一点我似乎无法弄明白。
任何意见都将受到赞赏。
我的计划是通过遍历字典列表找到所有唯一键,然后正确排序这些键,然后我可以使用键作为列标题创建一个csv文件。我知道我可以找到推出的唯一键并手动对其进行排序然后再读取已排序的文件,但这看起来很笨拙。
答案 0 :(得分:4)
在排序时只需提供一个足够聪明的功能作为键。
>>> (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)
答案 1 :(得分:2)
您可以使用正则表达式来提取密钥的不同部分,并使用它们进行排序。
如,
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
为了解释密钥提取过程,我们知道密钥具有某种模式。正则表达式在这里很有用。
r'Q_(\d+)_SUB_(\w+)_COLUMN_(\w+)_NUMB_(\d+)'
# ^ ^ ^ ^
# digits letters letters digits
# group 1 group 2 group 3 group 4
在正则表达式中,包含在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的方法,对模式只有更严格的要求。一旦你可以解决这个问题,创建适当的排序键应该很简单。
答案 2 :(得分:0)
假设密钥包含在列表中,请说出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)
在此之后,列表中的项目是看起来像
的元组 (123,17,D,C,Q_123_SUB_D_COLUMN_C_NUMB_17)
from operator import itemgetter
list_to_sort.sort(key=itemgetter(0,1,2,3)
我不确定itemgetter究竟做了什么,但这样做起来似乎更简单,但不如其他两种解决方案更优雅。
请注意,我安排了元组中的键,以便按照与键出现的方式不同的顺序进行排序。那是我没必要做的
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)
我更容易通过
跟踪第一个