【问题标题】:Create a list of tuples with adjacent list elements if a condition is true如果条件为真,则创建具有相邻列表元素的元组列表
【发布时间】:2016-11-10 02:42:37
【问题描述】:

我正在尝试创建一个元组列表,其中元组内容是数字9 和列表中它之前的数字。

输入列表:

myList = [1, 8, 9, 2, 4, 9, 6, 7, 9, 8]

所需的输出:

sets = [(8, 9), (4, 9), (7, 9)]

代码:

sets = [list(zip(myList[i:i], myList[-1:])) for i in myList if i==9]

当前结果:

[[], [], []]

【问题讨论】:

    标签: python list python-3.x tuples list-comprehension


    【解决方案1】:

    更简洁的 Pythonic 方法:

    >>> [(x,y) for x,y in zip(myList, myList[1:]) if y == 9]
    [(8, 9), (4, 9), (7, 9)]
    

    上面的代码是做什么的:

    • zip(some_list, some_list[1:]) 将生成相邻元素对的列表。
    • 现在使用该元组,在第二个元素等于9 的条件下进行过滤。你完成了:)

    【讨论】:

      【解决方案2】:

      您的部分问题是myList[i:i] 将始终返回一个空列表。切片的结尾是独占的,因此当您执行 a_list[0:0] 时,您会尝试获取存在于 索引 0 和索引 0 之间的 a_list 的元素。

      您在正确的轨道上,但您想自己压缩列表。

      [(x, y) for x, y in zip(myList, myList[1:]) if y==9]
      

      【讨论】:

      • 和我的回答完全一样 :)
      • @SuperSaiyan 除了你没有提到 OP 的主要问题,他们对myList[i:i] 的使用。
      【解决方案3】:

      您已经很接近了,如果您刚刚开始,我将向您展示一种可能更直观的替代方法:

      sets = [(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
      

      获取列表长度范围内的索引,如果i位置的值等于9,则抓取相邻元素。

      结果是:

      sets
      [(8, 9), (4, 9), (7, 9)]
      

      效率低于其他方法,但我决定取消删除它以向您展示一种不同的方法。您可以改用enumerate() 来加快速度:

      sets = [(myList[i-1], j) for i, j in enumerate(myList) if j == 9]
      

      请注意 myList[0] = 9 没有zip 的理解的行为和理解的行为的边缘情况下与zip不同的

      具体来说,如果myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8] 那么:

      [(myList[i-1], myList[i]) for i in range(len(myList)) if myList[i] == 9]
      # results in: [(8, 9), (8, 9), (4, 9), (7, 9)]
      

      同时:

      [(x, y) for x, y in zip(myList, myList[1:]) if y==9]
      # results in: [(8, 9), (4, 9), (7, 9)]
      

      由您决定哪些符合您的标准,我只是指出它们在所有情况下的行为都不相同。

      【讨论】:

        【解决方案4】:

        您也可以通过创建迭代器来实现不切片:

        l = myList = [1,8,9,2,4,9,6,7,9,8]
        
        it1, it2 = iter(l), iter(l)
        # consume first element from it2 -> leaving 8,9,2,4,9,6,7,9,8
        next(it2, "")
        # then pair up, (1,8), (8,9) ...
        print([(i, j) for i,j in zip(it1, it2) if j == 9])
        

        或使用pairwise recipe 来创建您的配对

        from itertools import tee, izip
        
        def pairwise(iterable):
            "s -> (s0,s1), (s1,s2), (s2, s3), ..."
            a, b = tee(iterable)
            next(b, None)
            return izip(a, b)
        

        如果使用python3,只需导入tee并使用常规zip

        【讨论】:

        • @Phillip,当你消费一个迭代器的一部分时,即 next(it2),你移动到下一个元素并且第一个元素被消费,所以在这个例子中,我们从 it2 的第二个元素开始我们压缩
        【解决方案5】:

        令人惊讶的是,没有人添加函数式方法。

        另一个替代答案是使用filter。此内置函数返回一个迭代器(Python2 中的列表),该迭代器由列表中存在的所有元素组成,这些元素为特定函数返回 True

        >>> myList = [1,8,9,2,4,9,6,7,9,8]
        >>> list(filter(lambda x:x[1]==9,zip(myList, myList[1:])))
        [(8, 9), (4, 9), (7, 9)]
        

        需要注意的是list call is needed only in python3+. detail in this post 中讨论了函数式方法和列表推导式之间的区别。

        【讨论】:

          【解决方案6】:

          我的解决方案类似于 Jim 的一种高级零索引检查

          myList = [9, 1, 8, 9, 2, 4, 9, 6, 7, 9, 8]
          
          [(myList[i-1], x) for i, x in enumerate(myList) if x==9 and i!=0]
          
          # [(8, 9), (4, 9), (7, 9)]
          

          【讨论】:

            猜你喜欢
            • 2021-12-08
            • 2015-04-27
            • 2020-03-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多