将列表中的唯一值聚合到新列表

时间:2018-07-27 18:24:23

标签: python

试图找到从python列表中聚合值(值对)的最佳方法。

foo = [
    {'color': 'yellow', 'type': 'foo'},
    {'color': 'yellow', 'type': 'bar'},
    {'color': 'red', 'type': 'foo'},
    {'color': 'red', 'type': 'foo'},
    {'color': 'green', 'type': 'foo'},
    {'color': 'red', 'type': 'bar'}
]

最终目标类似于

newFoo = [
    {'color': 'yellow', 'type': 'foo', 'count': 1},
    {'color': 'yellow', 'type': 'bar', 'count': 1},
    {'color': 'red', 'type': 'foo', 'count': 2},
    {'color': 'red', 'type': 'bar', 'count': 1},
    {'color': 'green', 'type': 'foo', 'count': 1}
]

我对python不太满意,但是一直在尝试实现它,但是据我所知:

def loop(ar):
    dik = []
    for line in ar:
        blah = []

        for k,v in line.items():
            blah.append({k,v})
        blah.append({'count':'1'})
    dik.append(blah)
    print(dik)

任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:2)

您可以使用Counter中的collections

from collections import Counter
from pprint import pprint

foo = [
    {'color': 'yellow', 'type': 'foo'},
    {'color': 'yellow', 'type': 'bar'},
    {'color': 'red', 'type': 'foo'},
    {'color': 'red', 'type': 'foo'},
    {'color': 'green', 'type': 'foo'},
    {'color': 'red', 'type': 'bar'}
]

c = Counter( tuple( (i['color'], i['type']) for i in foo))
pprint([{'color': k[0], 'type': k[1], 'count': v} for k, v in c.items()])

输出:

[{'color': 'yellow', 'count': 1, 'type': 'foo'},
 {'color': 'yellow', 'count': 1, 'type': 'bar'},
 {'color': 'red', 'count': 2, 'type': 'foo'},
 {'color': 'green', 'count': 1, 'type': 'foo'},
 {'color': 'red', 'count': 1, 'type': 'bar'}]

编辑:

如果要对新列表进行排序,可以执行以下操作:

l = sorted(newFoo, key=lambda v: (v['color'], v['type']), reverse=True)
pprint(l)

将打印:

[{'color': 'yellow', 'count': 1, 'type': 'foo'},
 {'color': 'yellow', 'count': 1, 'type': 'bar'},
 {'color': 'red', 'count': 2, 'type': 'foo'},
 {'color': 'red', 'count': 1, 'type': 'bar'},
 {'color': 'green', 'count': 1, 'type': 'foo'}]

编辑:

由于@MadPhysicist,您可以概括以上示例:

c = Counter(tuple(item for item in i.items()) for i in foo)
pprint([{**dict(k), 'count': v} for k, v in c.items()])

答案 1 :(得分:1)

如果您不介意重复,这是一个简单的选择。如果您只想要一个记录,那么安德烈(Andrej)的Counter答案就很好。

newFoo = [dict(d, **{'count': foo.count(d)}) for d in foo]
>>> newFoo

[{'color': 'yellow', 'type': 'foo', 'count': 1}, 
 {'color': 'yellow', 'type': 'bar', 'count': 1}, 
 {'color': 'red', 'type': 'foo', 'count': 2}, 
 {'color': 'red', 'type': 'foo', 'count': 2}, 
 {'color': 'green', 'type': 'foo', 'count': 1},
 {'color': 'red', 'type': 'bar', 'count': 1}]

答案 2 :(得分:0)

哈哈,这花了我更长的时间,我想承认,并且有很多更好的答案,但是我以一种老式的方式做到了这一点,也许这可以帮助您了解如何在没有精美库的情况下实现它。

# You clone the list before making any checks, 
# because you can't iterate an empty list.
new_foo = foo 

for old in foo: # for each item in the old list
    for new in new_foo: # we make a check to find that item in the new one
        if old['type'] == new['type'] and old['color'] == new['color']: # and if those 2 keys match
            if not 'count' in new: # we try to find the count key
                new['count'] = 1 # add it if it wasn't found
            else:
                new['count'] = new['count'] + 1 # sum 1 if it was found
            break # and then stop looking, break the 2nd loop.

这应该在我们要计数的每个项目上增加计数。但是,它使重复的计数没有计数键。

{'color': 'yellow', 'type': 'foo', 'count': 1}
{'color': 'yellow', 'type': 'bar', 'count': 1}
{'color': 'red', 'type': 'foo', 'count': 2}
{'color': 'red', 'type': 'foo'}
{'color': 'green', 'type': 'foo', 'count': 1}
{'color': 'red', 'type': 'bar', 'count': 1}

当我们首先克隆列表时,可悲的是那些仍然存在于我们的新列表中,所以让我们用它来过滤掉它们。

for item in new_foo:
    if not 'count' in item:
        new_foo.remove(item)

结果:

{'color': 'yellow', 'type': 'foo', 'count': 1}
{'color': 'yellow', 'type': 'bar', 'count': 1}
{'color': 'red', 'type': 'foo', 'count': 2}
{'color': 'green', 'type': 'foo', 'count': 1}
{'color': 'red', 'type': 'bar', 'count': 1}

我知道有更好的答案,但是我认为在接触高级技术之前,了解基本知识很重要。我们可以通过以下方式方便地检查字典中的键并将键添加到字典中:

if 'my_made_up_key' in my_dict: # check if exists

my_dict['my_made_up_key'] = my_value # add new key to a dict

答案 3 :(得分:0)

我尽我所能使用您的原始代码。我添加的内容是对事物进行排序,然后跟踪每个项目是否与前面的项目匹配。

`# list sort/count routine`
    def loop(ar):
        dik = []
        ar.sort() #this way we need only check the preceding one for a repeat
        #it does give the list sorted, which we believe is harmless
        blah={'color': '', 'type': '', 'count':0} #initialize blah to something that will not match
        for line in ar:
            if (blah['color']==line['color'])and (blah['type']==line['type']):
                blah['count']=blah['count']+1 #still accumulating count in blah
            else:#first of this one
                if (blah['color'])!='':#add previous one, if any
                    dik.append(blah)
                blah={'color': line['color'], 'type': line['type'], 'count':1}
        if (blah['color'])!='':#add the last one
                    dik.append(blah)
        return dik

    foo = [
        {'color': 'yellow', 'type': 'foo'},
        {'color': 'yellow', 'type': 'bar'},
        {'color': 'red', 'type': 'foo'},
        {'color': 'red', 'type': 'foo'},
        {'color': 'green', 'type': 'foo'},
        {'color': 'red', 'type': 'bar'}
    ]

    newFoo = loop(foo)
    print newFoo`