【问题标题】:Extract index of Non duplicate elements in python list提取python列表中非重复元素的索引
【发布时间】:2018-09-01 10:37:57
【问题描述】:

我有一个清单:

input = ['a','b','c','a','b','d','e','d','g','g']

我想要列表中除重复元素之外的所有元素的索引。

output = [0,1,2,5,6,8]

【问题讨论】:

标签: python algorithm search


【解决方案1】:

您应该遍历枚举列表并将每个元素添加到一组“已看到”元素并将索引添加到输出列表如果该元素尚未被看到(不在“看见”的集合)。

哦,input 这个名字覆盖了内置的input() 函数,所以我把它改名为input_list

output = []
seen = set()
for i,e in enumerate(input_list):
    if e not in seen:
        output.append(i)
        seen.add(e)

output 设为[0, 1, 2, 5, 6, 8]


为什么要使用套装?

你可能会想,既然可以做这样的事情,为什么还要使用集合:

[i for i,e in enumerate(input_list) if input_list.index(e) == i]

这会起作用,因为.index 会为您返回具有该值的列表中第一个元素的索引,因此如果您对照此检查元素的索引,您可以断言它是该元素的第一次出现并且过滤掉那些不是第一次出现的元素。

但是,这不如使用集合有效,因为list.index 需要 Python 遍历列表,直到找到元素(或没有找到)。这个操作是O(n) 复杂性,因为我们为input_list 中的每个元素调用它,所以整个解决方案将是O(n^2)

另一方面,与第一个解决方案一样,使用集合会产生O(n) 解决方案,因为检查一个元素是否为in 集合是复杂性O(1)(平均情况)。这是由于集合是如何实现的(它们就像列表,但每个元素都存储在其哈希的索引处,因此您可以计算一个元素的哈希并查看是否有一个元素来检查成员资格而不是迭代它 - 请注意,这是一个模糊的过度简化,但这是他们的想法)。

因此,由于每个成员资格检查都是O(1),并且我们对每个元素都执行此操作,因此我们得到一个比O(n^2) 解决方案好得多的O(n) 解决方案。

【讨论】:

    【解决方案2】:

    你可以做这样的事情,检查计数(虽然这是计算量很大的):

    indexes = []
    for i, x in enumerate(inputlist):
        if (inputlist.count(x) == 1
            and x not in inputlist[:i]):
            indexes.append(i)
    

    这会检查以下内容:

    1. 如果项目只出现一次。如果是,请继续...
    2. 如果该项目到目前为止还没有出现在列表中。如果是,请添加到结果列表中

    【讨论】:

    • 这将给出唯一元素的索引,而不是问题中要求的元素出现的第一个索引。
    【解决方案3】:

    如果您不介意最后一次重复出现的索引,而是使用 Python 3.6+,这里有一个替代解决方案:

    list(dict(map(reversed, enumerate(input))).values())
    

    这会返回:

    [3, 4, 2, 7, 6, 9]
    

    【讨论】:

      【解决方案4】:

      这是使用zipreversed 的单行代码

      >>> input = ['a','b','c','a','b','d','e','d','g','g']
      >>> sorted(dict(zip(reversed(input), range(len(input)-1, -1, -1))).values())
      [0, 1, 2, 5, 6, 8]
      

      【讨论】:

        【解决方案5】:

        此问题缺少pandas 解决方案。 ?

        >>> import pandas as pd
        >>> inp = ['a','b','c','a','b','d','e','d','g','g']
        >>> 
        >>> pd.DataFrame(list(enumerate(inp))).groupby(1).first()[0].tolist()
        [0, 1, 2, 5, 6, 8]
        

        【讨论】:

          【解决方案6】:

          另一个版本,在列表推导中使用副作用。

          >>> xs=['a','b','c','a','b','d','e','d','g','g']
          >>> seen = set()
          >>> [i for i, v in enumerate(xs) if v not in seen and not seen.add(v)]
          [0, 1, 2, 5, 6, 8]
          

          列表推导过滤尚未见过的值的索引。 诀窍在于not seen.add(v) 始终为真,因为seen.add(v) 返回None。 由于短路评估,当且仅当v 不可见时才会执行seen.add(v),并在运行中向seen 添加新值。

          最后, seen 包含输入列表的所有值。

          >>> seen
          {'a', 'c', 'g', 'b', 'd', 'e'}
          

          注意:在列表理解中使用副作用通常是个坏主意, 但有时你可能会看到这个技巧。

          【讨论】:

            猜你喜欢
            • 2022-08-17
            • 1970-01-01
            • 2019-06-28
            • 2020-11-20
            • 2018-07-06
            • 2020-10-31
            • 1970-01-01
            • 2011-02-06
            • 1970-01-01
            相关资源
            最近更新 更多