在python中在循环内编写循环的更简洁方法

时间:2015-08-12 06:28:35

标签: python for-loop

我有一个对象列表,这些对象是我的代码中的特定类,如此,

[object1, object2, object3, object4, object5, object6]

即此类有两个属性:class.scoreclass.id

我可能有相同ID的对象。例如:

[object1.id, object2.id, object3.id, object4.id, object5.id, object6.id] = [1, 2, 3, 4, 2, 3]

但得分不同。例如:

[object1.score, object2.score, object3.score, object4.score, object5.score,
object6.score] = [0.25, 0.55, 0.6, 0.4, 0.30, .33]

我想做的是让列表没有这个对象的重复,但是 添加分数。因此,对于前面的示例,输出将是:

[object1.id, object2.id, object3.id, object4.id] = [1, 2, 3, 4]
[object1.score, object2.score, object3.score, object4.score] = [.25, .85, .93, .4]

我设法用两个for循环来做到这一点:

k = 1
    for object in list_of_objects:
        j = 1
        for object2 in list_of_objects:
            if object.id == object2.id and j > k:
                object.score = object.score + object2.score
                list_of_objects.remove(object2)
            j += 1
        k += 1

但是我希望用更多的python-ish来做这件事,就像这样:

newlist[:] = [ x for x in list_of_objects if certain_condition(x)]

感谢。

3 个答案:

答案 0 :(得分:6)

itertools.groupby完全符合这种情况 https://docs.python.org/2/library/itertools.html#itertools.groupby

from itertools import groupby
# object.id is our key:
keyfunc = lambda obj: obj.id
list_of_objects = sorted(list_of_objects, key=keyfunc)

scores = [sum(score_list) for id, score_list in groupby(list_of_objects, keyfunc)]
ids = [id for id, score_list in groupby(list_of_objects, keyfunc)]

答案 1 :(得分:2)

通常使用字典来检测已经看过的对象:

seen = {}
for x in my_objects:
    if x.id in seen:
        seen[x.id].score += x.score
    else:
        seen[x.id] = x
my_objects[:] = seen.values()

使用字典会使计算O(n)而不是O(n²)

答案 2 :(得分:1)

您可以通过提供额外的自定义功能,在一行内使用Python Built-in Functions

def r(l, o):
    if len(l) > 0 and l[-1].id == o.id:
        l[-1].score += o.score
    else:
        l.append(o)
    return l

key = attrgetter('id')

然后只需将reduce功能与sorted以及上述自定义功能结合使用:

list_of_objects = reduce(r, sorted(list_of_objects, key=key), [])

然后你会得到你需要的东西:

[1: 0.25, 2: 0.85, 3: 0.93, 4: 0.4]