【问题标题】:Get index from a list where the key changes, groupby从键更改的列表中获取索引,groupby
【发布时间】:2011-09-30 20:30:31
【问题描述】:

我有一个如下所示的列表:

myList = [1, 1, 1, 1, 2, 2, 2, 3, 3, 3]

我想要做的是记录列表中项目更改值的索引。因此,对于我上面的列表,它将是 3、6。

我知道像这样使用 groupby:

[len(list(group)) for key, group in groupby(myList)]

将导致:

[4, 3, 3]

但我想要的是组开始/结束的索引,而不仅仅是组中的项目数。我知道我可以开始对每个连续组计数 1 求和以获得索引,但我认为可能有一种更清洁的方法。

想法表示赞赏。

【问题讨论】:

    标签: python list indexing group-by


    【解决方案1】:

    只需使用enumerate 与列表一起生成索引。

    from operator import itemgetter
    from itertools import groupby
    myList = [1, 1, 1, 1, 2, 2, 2, 3, 3, 3]
    
    [next(group) for key, group in groupby(enumerate(myList), key=itemgetter(1))]
    # [(0, 1), (4, 2), (7, 3)]
    

    这为每个组提供了一对(start_index, value)

    如果你真的只想要[3, 6],你可以使用

    [tuple(group)[-1][0] for key, group in 
            groupby(enumerate(myList), key=itemgetter(1))][:-1]
    

    indexes = (next(group)[0] - 1 for key, group in
                    groupby(enumerate(myList), key=itemgetter(1)))
    
    next(indexes)
    indexes = list(indexes)
    

    【讨论】:

    • 这很棒,因为它提供了变化的索引和价值
    • 如果我只想返回索引值而不是键,我需要修改哪些代码?还是 group by 不可能?
    • 请原谅我对这个话题的无知,你的第二个答案是我需要的,只需提供索引。
    • @user965586 没什么好原谅的;很高兴我能帮上忙。
    • 这个解决方案很可爱,但是太复杂了,没用。所讨论的任务非常简单,因此应该需要一个简单的解决方案。每当我使用itemgetter 时,我该死的更需要它。任何查看您的代码的人都很难弄清楚这行代码的作用。这很明显,因为 OP 甚至没有意识到您的解决方案一开始就解决了他的问题。
    【解决方案2】:
    [i for i in range(len(myList)-1) if myList[i] != myList[i+1]]
    

    在 Python 2 中,将 range 替换为 xrange

    【讨论】:

    • 另一种选择:[i for i, (a, b) in enumerate(zip(myList, myList[1:])) if a != b],这应该更快,但缺点是它需要 myList 的副本。
    • @agf:我并不是要粗鲁,但您的评论毫无意义。你认为 Python 列表是作为链表实现的吗?恰恰相反;事实上,它们基本上都是数组,所以列表访问是 O(1)。见wiki.python.org/moin/TimeComplexity
    • @machineyearning 你说得对,我不知道我在想什么——我知道它们不是链表,只是脑子有问题。纠正某人没有什么粗鲁的:)。 +1,这是一个好方法——只要你正在处理的任何东西都有长度并且是可索引的(就像问题中的例子一样)。
    【解决方案3】:
    >>> x0 = myList[0]
    ... for i, x in enumerate(myList):
    ...     if x != x0:
    ...         print i - 1
    ...         x0 = x
    3
    6
    

    【讨论】:

    • 这是一个不错的简单示例,但我会先使用it = iter(myList),然后使用x0 = next(it),然后使用for i, x in enumerate(it)print i,这样您就不必查看列表中的第一项两次,不必每次都做减法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    相关资源
    最近更新 更多