选择满足其他条件的列表中最早的条目

时间:2011-02-11 16:50:31

标签: python list dictionary

说我有一个列表L1L1中的条目有4个部分,格式如下cat1, cat2, date, ID。列表按照cat1条目按字母顺序排序,然后按cat2条目按字母顺序排序,然后按最早date排序。我想要这个列表的一个子集,其中包含每个cat1, cat2对的最早日期条目。这是我已经执行此操作的代码:

L1=[A, X, 2008-06-01, 1858
A, X, 2008-12-05, 1905
B, X, 2001-08-08, 1149
B, Y, 2006-03-05, 1638
B, Y, 2009-06-09, 1950
C, X, 2005-12-01, 1611
C, X, 2006-08-08, 1689
C, X, 2006-11-22, 1712
C, X, 2008-04-22, 1842
C, Y, 2008-12-05, 1816
C, Y, 2008-12-05, 1821
C, Y, 2008-12-05, 1882
C, Z, 2008-12-05, 1905
C, Z, 2009-06-01, 1935
C, Z, 2009-06-09, 1950
D, X, 2009-11-06, 1989
D, Y, 2008-12-05, 1905
D, Z, 2008-12-05, 1905
D, Z, 2008-12-05, 1905
E, X, 2008-12-05, 1905
E, Z, 2008-12-05, 1905
F, Y, 2008-12-05, 1905
G, X, 2008-12-05, 1905
G, Z, 2007-12-01, 1807]

L2=[j.next() for i, j in itertools.groupby(L1, lambda x: x.split(",", 2)[:2])]

L2=[A, X, 2008-06-01, 1858
B, X, 2001-08-08, 1149
B, Y, 2006-03-05, 1638
C, X, 2005-12-01, 1611
C, Y, 2008-12-05, 1816
C, Z, 2008-12-05, 1905
D, X, 2009-11-06, 1989
D, Y, 2008-12-05, 1905
D, Z, 2008-12-05, 1905
E, X, 2008-12-05, 1905
E, Z, 2008-12-05, 1905
F, Y, 2008-12-05, 1905
G, X, 2008-12-05, 1905
G, Z, 2007-12-01, 1807]

现在的诀窍是,我想要每个cat1, cat2对的最早条目,其中ID位于dict1和{{1}中的< = 3个键中的值列表中}}。换句话说,一旦找到dict2对的最早条目,就应该在每个cat1, cat2dict1中测试,如果发现dict2中包含ID两个字典的4+键的值列表,它应该转到cat1, cat2对的下一个最早条目,并且为了将条目添加到L2,其ID应该在3 dict1dict2中的密钥或更少密钥。我不太确定如何解决这个问题...也许使用re.search或其他什么?

dict1[key]=[ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID]    
dict2[key]=[ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID]

所以不是L2只有每个cat1, cat2对的最早条目,它将包含最早的条目,其中该条目的ID不在4 +键的ID列表中同时使用dict1dict2

2 个答案:

答案 0 :(得分:1)

如果dict1dict2的值列表不是太大,您可以先生成所有有效ID的集合,然后过滤L1以仅包含那些元组(X,Y,日期) ,ID)其ID在值ID集合中:

import collections
def valid_ids(*dcts):
    valid=collections.defaultdict(int)
    for dct in dcts:
        for key,value in dct.iteritems():
            valid[value]+=1
    return set(value for value,count in valid.iteritems() if count<=3)

ids=valid_ids(dict1,dict2)

L1_filtered=[text.split(',') for text in L1 if text.split(',')[-1].strip() in ids]
L2 = [j.next() for i, j in itertools.groupby(L1_filtered, lambda x: x.split(",", 2)[:2])]

请注意,如果dict1dict2具有包含大量ID的值列表,则上述方法并不理想,因为您将浪费大量时间来确定值ID的集合在形成L2时,您可能只需要一点这些数据。


使用Hugh Bothwell的想法,如果dict1dict2具有较大的值列表,那么根据需要检查特定ID是否有效可能需要付费:

def is_valid(ID,*dcts):    
    return sum(1 for dct in dcts
               for key,value in dct.iteritems()
               if ID in value) <= 3       

L2=[]
for key, group in itertools.groupby(L1, lambda x: x.split(",", 2)[:2]):
    for text in group:
        X,Y,date,ID = text.split(',')
        X = X.strip()
        Y = Y.strip()
        date = date.strip()
        ID = ID.strip()
        if is_valid(ID,dict1,dict2):
            L2.append(X,Y,date,ID)
            break
    else:
        # There is no valid ID for this group!
        continue

请注意,如果您使用第一种方法valid_ids,则只需循环一次。如果您使用第二种方法,则为每个组(唯一XY对)至少循环一次dicts,并且每个组可能多次。

我的猜测是大多数数据集的第一种方法会更快,但用真实数据分析这两种方法可能是最安全的方法。

答案 1 :(得分:0)

我认为你需要像

这样的东西
L2 = []
for xy,rem in itertools.groupby(L1, lambda x: x.split(",", 2)[:2]):
    for s in rem:
        date,id = s.split(",")
        if TEST_ID(id):
            L2.append(s)
            break