【问题标题】:python unique list based on item基于项目的python唯一列表
【发布时间】:2013-10-28 03:25:48
【问题描述】:

我有一个清单

old_list = [
        (1, 'AAA', None, 1),
        (2, 'AAA', 'x', 0),
        (5, 'AAB', 'z', 1),
        (6, 'ABB', 'x', 1),
        (9, 'ABB', 'x', 1)]

我希望如何获得一个具有唯一 i[1] 和更大 id i[0] 的新列表,就像这个结果

new_list = [
        (2, 'AAA', 'x', 0),
        (5, 'AAB', 'z', 1),
        (9, 'ABB', 'x', 1)]
]

有人可以帮我吗?

【问题讨论】:

    标签: python list unique


    【解决方案1】:

    您可以使用itertools.groupby

    old_list = [
            (1, 'AAA', None, 1),
            (2, 'AAA', 'x', 0),
            (5, 'AAB', 'z', 1),
            (6, 'ABB', 'x', 1),
            (9, 'ABB', 'x', 1)]
    from itertools import groupby
    from operator import itemgetter
    print [sorted(list(group), key=itemgetter(0))[-1]
           for key, group in groupby(old_list, key=itemgetter(1))]
    

    输出

    [(2, 'AAA', 'x', 0), (5, 'AAB', 'z', 1), (9, 'ABB', 'x', 1)]
    

    如果old_list还没有排序,可以这样排序

    old_list = sorted([
            (1, 'AAA', None, 1),
            (2, 'AAA', 'x', 0),
            (5, 'AAB', 'z', 1),
            (6, 'ABB', 'x', 1),
            (9, 'ABB', 'x', 1)], key=itemgetter(1))
    

    【讨论】:

    • (禁止投票)。更喜欢 operator.itemgetter 而不是 lambda。您也不需要那种单独的组。只需选择列表中的最后一项。如果项目实际上没有排序,则在应用 groupby 之前按第二个元素然后第一个元素对它们进行排序。
    • @Abhijit 哦。谢谢你的建议。但是,这样做有什么具体原因吗?
    • 1.如果图书馆中有可用的东西,则喜欢它而不是滚动一个。 2. 如果你看到 python 是如何进化的,有一个普遍的共识是不要使用lambda
    • 谢谢@Abhijit。我更新了它。顺便说一句,将来lambda 的替代品是什么?
    【解决方案2】:

    你可以这样做:

    d={}
    for t in old_list:
        d.setdefault(t[1],[]).append(t)
        
    new_list=[]    
    for k in sorted(d):       # sort by the keys ('AAA', 'AAB', etc)
        new_list.append(max(d[k], key=lambda t: t[0]))    # max index (t[0])
    # [(2, 'AAA', 'x', 0), (5, 'AAB', 'z', 1), (9, 'ABB', 'x', 1)]
    

    编辑

    如果没有重复 ID 的可能性,您可以这样做:

    d={}
    for t in old_list:
        d.setdefault(t[1],[]).append(t)
        
    new_list=[]    
    for k in sorted(d):
        new_list.append(d[k][-1]) 
    

    这与样本数据的答案相同。


    编辑 2,计时

    from collections import defaultdict
    
    s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
    
    def f1():
        d = defaultdict(list)
        for k, v in s:
            d[k].append(v)
            
        return d.items()
        
    def f2():
        d={}
        for k, v in s:
            d.setdefault(k, []).append(v)
            
        return d.items()            
      
    if __name__ == '__main__':
        import timeit
        import sys
        print(sys.version)
        print('defaultdict:', timeit.timeit("f1()", setup="from __main__ import f1, s"))
        print('setdefault:', timeit.timeit("f2()", setup="from __main__ import f2, s"))
    

    打印:

    3.3.2 (default, Jul  6 2013, 10:40:18) 
    [GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)]
    defaultdict: 2.384568103996571
    setdefault: 1.6183147379779257
    

    帖子的时间安排表明这是一种更快的方法:

    from __future__ import print_function 
    from collections import OrderedDict
    import itertools
    from operator import itemgetter
    
    old_list = [
            (1, 'AAA', None, 1),
            (2, 'AAA', 'x', 0),
            (5, 'AAB', 'z', 1),
            (6, 'ABB', 'x', 1),
            (9, 'ABB', 'x', 1)]
            
    def f1():
        d={}
        for t in old_list:
            d.setdefault(t[1],[]).append(t)
    
        new_list=[]    
        for k in sorted(d):
            new_list.append(d[k][-1]) 
        
        return new_list    
                
    def f2():
        nl = sorted(old_list, key=itemgetter(2,1))
        return OrderedDict((elem[1], elem) 
                 for elem in nl).values()    
                
    def f3():
        nl=sorted(old_list, key=lambda x: x[1])
        return [sorted(list(group), key=lambda x:x[0], reverse=True)[0]
                   for key, group in itertools.groupby(nl, key=lambda x:x[1])]                  
      
    if __name__ == '__main__':
        import timeit
        import sys
        print(sys.version) 
        print('drewk:',timeit.timeit("f1()", setup="from __main__ import f1, old_list"))
        print('Abhijit:', timeit.timeit("f2()", setup="from __main__ import f2, old_list, OrderedDict, itemgetter"))
        print('thefourtheye:', timeit.timeit("f3()", setup="from __main__ import f3, old_list, itertools"))
    

    打印:

    2.7.5 (default, Aug 25 2013, 00:04:04) 
    [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)]
    drewk: 3.30526208878
    Abhijit: 20.5611379147
    thefourtheye: 13.2195081711
    

    【讨论】:

    • 我相信您忽略了字典中插入的最新元素仍然存在的事实。所以你不需要遍历列表并找到最大值的后处理。此外,defaultdict 优于 setdefault。最后,不使用OrderedDict,你已经丢弃了一个已经排序的数据。所以总的来说这是一个糟糕的方法。
    • @Abhijit: A) 哪里说defaultdictsetdefault 更“首选”; B)OP 说“我想要......更大的 id i[0]”他没有说这是按 ID 排序的或没有重复的; C) OrderedDict 是用 Python 编写的。按 t[1] 的键排序很可能比保持 Python vs C dict 更快。当然,C dict 比 OrderedDict 快得多
    • Where is it stated that defaultdict is 'preferred' over setdefault。阅读docsSorting by the keys of t[1] is very probably faster than keeping a Python vs C dict 较小子列表的多重排序不能比 OrderedDict 快
    • @Abhijit:请查看时间安排。使用该链接页面上的示例,defaultdict 并不比 setdefault 更快也更容易
    • 你的时间安排有缺陷;对于这么小的数据集,对象的创建时间起着不成比例的重要作用。使用文字 {} 比调用工厂函数 (defaultdict()) 快得多。
    猜你喜欢
    • 2012-05-29
    • 2016-11-04
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多