我有一个字典结构如下:
{ID:[{*},{*},{*},...]}
,即每个ID都有一个字典列表,每个字典代表一个游戏中的动作。每个字典的内容(由*表示)由这些键构成,列表由gameTime
字段排序:
userID gameTime gameCode shortDesc d01 d02 d03 d04 chapter level playCnt
我必须编写一个.csv文件,其中包含符合某些条件的 userIDs 对应的数据。即,我必须存储与用户相关的数据,这些数据在某些时候会采取一些措施。 例如,我必须拥有与每个 userID 相关的信息,这些信息在某些时候具有这些键/值:
shortDesc:BADGE_OPT
d01:OPT-IN
由于d01
是与shortDescription
相关的数据,我知道当我找到shortDesc : BADGE_OPT
时,我必须查看d01 : OPT-IN
但是我也可以找到一系列:
shortDesc:BADGE_OPT / d01:OPT-IN
shortDesc:BADGE_OPT / d01:OPT-OUT
然后,我必须在d01 = OPT_IN
时存储信息,即必须丢弃任何d01 = OPT_OUT / d01 = OPT_IN
之间的信息。
因此,在某些情况下,BADGE_OPT
已启用,而且它永远不会被证明。或者我可以找到一个转入/转出的序列。
我知道我可以遍历我的词典列表,在我第一次找到d01 = OPT_IN
时开始录制(在另一个列表中),在找到d01 = OPT_OUT
时停止等等。但是我想知道是否有 pythonic 方法来做到这一点(获取这些细节部分或信息,或删除不必要的部分或信息)。
到目前为止,我正在尝试这样的事情:
import numpy
import csv
import fileinput
import sys
from itertools import chain
def process_data(file_path):
users = {}
# Open the .csv file and creates a dict of actions
with open(file_path, 'rb') as csvfile:
spamreader = csv.DictReader(csvfile, delimiter='\t', quoting=csv.QUOTE_NONE)
for row in spamreader:
conditions = list(row[condition_name[i]] == condition_value[i] for i in range(len(condition_name)))
if row[event_name] == event_value and all(conditions) == True:
# Add an empty list for 'userID' if it is not registered yet in dict
user = row['subjectID']
actions = users.get(user, [])
# Delete the 'userID' from the information
del row['subjectID']
# Add a register of actions for this user
actions.append(row)
# Update its values
users[user] = actions
# Sort each list of actions based on time
for user, event_list in users.iteritems():
users[user] = sorted(event_list, key=lambda k: k[data])
# Write a .csv to be consumed by the app
with open('eventsInput.txt', 'w') as csvfile:
writer = csv.writer(csvfile, delimiter='\t')
# Key is the user ID
# Value is a list of dictionaries of its action per time
for user, event_list in users.iteritems():
events = []
# Produces pairs of event/time
for event_dict in event_list:
event = " ".join(event_dict[e] for e in event_fields)
time = event_dict[data]
events.append(event)
events.append(time)
writer.writerow([user, 1, 2, 0, 4, str(5)] + events)
# Pos-processing
if len(pos_condition_name) == 0:
return
f = fileinput.input('eventsInput.txt', inplace=True)
w = csv.writer(sys.stdout)
spamreader = csv.DictReader(f, delimiter='\t', quoting=csv.QUOTE_NONE)
for row in spamreader:
conditions = list(row[pos_condition_name[i]] == pos_condition_value[i] for i in range(len(pos_condition_name)))
if all(conditions) == True:
w.writerow(row)
event_name = 'shortDesc'
event_value = 'ANGLE_RULE_ACTION'
event_fields = ['d01', 'd02', 'd03', 'd04']
condition_name = ['level', 'chapter']
condition_value = ['3', '3']
pos_condition_name = ['shortDesc']
pos_condition_value = ['BADGE_OPT']
但这至少有两个原因并不起作用。首先,每个字典都没有必要包含字段shortDesc = BADGE_OPT
和d01 = OPT_IN
。这在这个数据中甚至没有意义。但是,我无法使用any
进行测试,因为稍后可能会出现这种情况,而且我只需要存储与条件值为in
的时间段相关的信息。
答案 0 :(得分:1)
我说解决方案的外部部分最好用几个特殊的pythonic for循环结构来解决:
for id,actionlist in bigdict.items():
opted_in=False # initial state
for index,stardict in enumerate(actionlist):
if stardict['shortDesc'] == 'BADGE_OPT':
if ( stardict['d01'] == 'OPT-IN') opted_in = True
if ( stardict['d01'] == 'OPT-OUT' opted_in = False
# act depending on opted_in state
它看起来很笨拙,但我已经避免了opted_in = ( stardict['d01'] == 'OPT-IN' )
,因为它不清楚d01仅限于拥有这两个值。如果try ... except KeyError
不能包含stardict
或shortDesc
密钥,您可以将最后三行放在d01
块中。
那该怎么办?当opt_in为真时,我会用stardicts建立一个判决,但我可能不完全理解这个问题。所以
outdict={}
for id,actionlist in bigdict.items():
opted_in=False # initial state
outdict[id] = []
for index,stardict in enumerate(actionlist):
if stardict['shortDesc'] == 'BADGE_OPT':
if ( stardict['d01'] == 'OPT-IN') opted_in = True
if ( stardict['d01'] == 'OPT-OUT' opted_in = False
if opted_in:
outdict[id].append( stardict)
然后处理判决。注意,没有复制标准,只是将相同的标准分配给存储在新结果中的新列表,因此它应该是可接受的快速。
NB未经测试。