字典列表中的Pythonic搜索

时间:2015-09-23 20:37:08

标签: python search dictionary

我有一个字典结构如下:

{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_OPTd01 = OPT_IN。这在这个数据中甚至没有意义。但是,我无法使用any进行测试,因为稍后可能会出现这种情况,而且我只需要存储与条件值为in的时间段相关的信息。

1 个答案:

答案 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不能包含stardictshortDesc密钥,您可以将最后三行放在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未经测试。