【问题标题】:More concise way of writing a loop inside a loop in python在python中的循环内编写循环的更简洁的方法
【发布时间】:2016-11-22 07:07:55
【问题描述】:

我的代码中有一个特定类的对象列表,如下所示,

[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]

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

[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 的方式来做这件事,类似于:

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

谢谢。

【问题讨论】:

  • 你关心最终名单的顺序吗?
  • 两个相同的对象怎么会有不同的属性?
  • @RenaeLider,我不认为它存在 Python id(),它只是一个名为 id 的属性。我不认为第一个列表中的重复意味着它是同一个对象(尽管它确实暗示了这一点)。
  • @Cyphase 不是真的,我更关心只保留一个具有正确分数总和的唯一 ID

标签: python for-loop


【解决方案1】:

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)]

【讨论】:

  • 但我想更改对象列表而不是创建新列表@frank
【解决方案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²)

【讨论】:

  • @RenaeLider:一套什么?如果你只保留.id,一旦你看到它是一个已经见过的对象,你还需要找到原件来添加分数
  • 我可以通过my_objects[:] = list(seen.values()) 来保持类结构吗?
  • @DiegoAgher:是的,seen.values()score 字段已递增到的原始对象。如果分配回原始列表,则不需要 list() 调用(我编辑了删除它的帖子)。
【解决方案3】:

您可以通过提供额外的自定义函数在一行中使用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]

【讨论】:

    猜你喜欢
    • 2014-01-26
    • 2012-10-20
    • 1970-01-01
    • 2019-01-04
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    相关资源
    最近更新 更多