【问题标题】:How to get first element in a list of tuples?如何获取元组列表中的第一个元素?
【发布时间】:2012-08-21 22:48:06
【问题描述】:

我有一个如下所示的列表,其中第一个元素是 id,另一个是字符串:

[(1, u'abc'), (2, u'def')]

我只想从这个元组列表中创建一个 id 列表,如下所示:

[1,2]

我将在__in 中使用这个列表,所以它需要是一个整数值列表。

【问题讨论】:

    标签: python list


    【解决方案1】:
    >>> a = [(1, u'abc'), (2, u'def')]
    >>> [i[0] for i in a]
    [1, 2]
    

    【讨论】:

      【解决方案2】:

      使用zip函数解耦元素:

      >>> inpt = [(1, u'abc'), (2, u'def')]
      >>> unzipped = zip(*inpt)
      >>> print unzipped
      [(1, 2), (u'abc', u'def')]
      >>> print list(unzipped[0])
      [1, 2]
      

      编辑(@BradSolomon): 以上适用于 Python 2.x,其中zip 返回一个列表。

      在 Python 3.x 中,zip 返回一个迭代器,下面的等价于上面的:

      >>> print(list(list(zip(*inpt))[0]))
      [1, 2]
      

      【讨论】:

      • 这需要单独导入吗?
      • @JuliandotNut 不,它是一个内置函数。 (在 Python 2.x 中)
      • 为什么需要对list 进行第二次强制转换?
      • 我知道这不是公认的答案,但这极大地帮助了我刚刚完成的任务。谢谢!
      【解决方案3】:

      你的意思是这样的吗?

      new_list = [ seq[0] for seq in yourlist ]
      

      您实际上拥有的是 tuple 对象列表,而不是集合列表(正如您最初的问题所暗示的那样)。如果它实际上是一个集合列表,那么没有第一个元素,因为集合没有顺序。

      在这里,我创建了一个平面列表,因为通常这似乎比创建一个包含 1 个元素的元组的列表更有用。但是,您只需将 seq[0] 替换为 (seq[0],) 即可轻松创建包含 1 个元素的元组的列表。

      【讨论】:

      • 我试过了。它给出了这个错误:int() argument must be a string or a number, not 'QuerySet'
      • @wasimbhalli -- int() 不在我的解决方案中,因此您看到的异常必须稍后出现在代码中。
      • 我已经更新了问题,我需要稍后在__in使用这个列表来过滤数据
      • 什么是__in? -- 根据您给出的示例输入,这将创建一个整数列表。但是,如果您的元组列表不是以整数开头,那么您将不会获得整数,您需要通过 int 将它们设为整数,或者尝试找出为什么您的第一个元素无法转换为一个整数。
      • new_list = [ seq[0] for seq in yourlist if type(seq[0]) == int] 工作吗?
      【解决方案4】:

      这就是operator.itemgetter 的用途。

      >>> a = [(1, u'abc'), (2, u'def')]
      >>> import operator
      >>> b = map(operator.itemgetter(0), a)
      >>> b
      [1, 2]
      

      itemgetter 语句返回一个函数,该函数返回您指定的索引处的元素。和写的一模一样

      >>> b = map(lambda x: x[0], a)
      

      但我发现itemgettermore explicit更清晰。

      这对于制作紧凑的排序语句很方便。例如,

      >>> c = sorted(a, key=operator.itemgetter(0), reverse=True)
      >>> c
      [(2, u'def'), (1, u'abc')]
      

      【讨论】:

        【解决方案5】:

        你可以使用“元组解包”:

        >>> my_list = [(1, 'abc'), (2, 'def')]
        >>> my_ids = [idx for idx, val in my_list]
        >>> my_ids
        [1, 2]
        

        在迭代时,每个元组都被解包,其值被设置为变量idxval

        >>> x = (1, 'abc')
        >>> idx, val = x
        >>> idx
        1
        >>> val
        'abc'
        

        【讨论】:

          【解决方案6】:

          我认为比较不同方法的运行时可能很有用,所以我做了一个基准测试(使用 simple_benchmark 库)

          I) 具有 2 个元素的元组的基准测试

          正如您可能期望的那样,通过索引 0 从元组中选择第一个元素表明它是最接近解包解决方案的最快解决方案,因为它期望正好 2 个值

          import operator
          import random
          
          from simple_benchmark import BenchmarkBuilder
          
          b = BenchmarkBuilder()
          
          
          
          @b.add_function()
          def rakesh_by_index(l):
              return [i[0] for i in l]
          
          
          @b.add_function()
          def wayneSan_zip(l):
              return list(list(zip(*l))[0])
          
          
          @b.add_function()
          def bcattle_itemgetter(l):
               return list(map(operator.itemgetter(0), l))
          
          
          @b.add_function()
          def ssoler_upacking(l):
              return [idx for idx, val in l]
          
          @b.add_function()
          def kederrack_unpacking(l):
              return [f for f, *_ in l]
          
          
          
          @b.add_arguments('Number of tuples')
          def argument_provider():
              for exp in range(2, 21):
                  size = 2**exp
                  yield size, [(random.choice(range(100)), random.choice(range(100))) for _ in range(size)]
          
          
          r = b.run()
          r.plot()
          

          II) 具有 2 个或更多元素的元组的基准测试

          import operator
          import random
          
          from simple_benchmark import BenchmarkBuilder
          
          b = BenchmarkBuilder()
          
          @b.add_function()
          def kederrack_unpacking(l):
              return [f for f, *_ in l]
          
          
          @b.add_function()
          def rakesh_by_index(l):
              return [i[0] for i in l]
          
          
          @b.add_function()
          def wayneSan_zip(l):
              return list(list(zip(*l))[0])
          
          
          @b.add_function()
          def bcattle_itemgetter(l):
               return list(map(operator.itemgetter(0), l))
          
          
          @b.add_arguments('Number of tuples')
          def argument_provider():
              for exp in range(2, 21):
                  size = 2**exp
                  yield size, [tuple(random.choice(range(100)) for _
                               in range(random.choice(range(2, 100)))) for _ in range(size)]
          
          from pylab import rcParams
          rcParams['figure.figsize'] = 12, 7
          
          r = b.run()
          r.plot()
          

          【讨论】:

            【解决方案7】:

            如果元组是唯一的,那么这可以工作

            >>> a = [(1, u'abc'), (2, u'def')]
            >>> a
            [(1, u'abc'), (2, u'def')]
            >>> dict(a).keys()
            [1, 2]
            >>> dict(a).values()
            [u'abc', u'def']
            >>> 
            

            【讨论】:

            • 这将丢失订单。不过,它可能适用于ordereddict
            • 如果 2 个或更多元组具有相同的第一个元素,那么您的解决方案将不起作用
            【解决方案8】:

            从性能的角度来看,在python3.X中

            • [i[0] for i in a]list(zip(*a))[0] 是等价的
            • 它们比list(map(operator.itemgetter(0), a))

            代码

            import timeit
            
            
            iterations = 100000
            init_time = timeit.timeit('''a = [(i, u'abc') for i in range(1000)]''', number=iterations)/iterations
            print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = [i[0] for i in a]''', number=iterations)/iterations - init_time)
            print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = list(zip(*a))[0]''', number=iterations)/iterations - init_time)
            

            输出

            3.491014136001468e-05

            3.422205176000717e-05

            【讨论】:

              【解决方案9】:

              当我跑的时候(如上所述):

              >>> a = [(1, u'abc'), (2, u'def')]
              >>> import operator
              >>> b = map(operator.itemgetter(0), a)
              >>> b
              

              而不是返回:

              [1, 2]
              

              我收到了这个作为回报:

              <map at 0xb387eb8>
              

              我发现我必须使用 list():

              >>> b = list(map(operator.itemgetter(0), a))
              

              使用此建议成功返回列表。也就是说,我对这个解决方案很满意,谢谢。 (使用 Spyder、iPython 控制台、Python v3.6 测试/运行)

              【讨论】:

                【解决方案10】:

                我想知道为什么没有人建议使用 numpy,但现在检查后我明白了。它可能不是混合类型数组的最佳选择。

                这将是 numpy 中的解决方案:

                >>> import numpy as np
                
                >>> a = np.asarray([(1, u'abc'), (2, u'def')])
                >>> a[:, 0].astype(int).tolist()
                [1, 2]
                

                【讨论】:

                  【解决方案11】:

                  要获取列表或元组的元素,您可以遍历列表或元组

                  a = [(1, u'abc'), (2, u'def')]
                  
                  list1 = [a[i][0] for i in range(len(a))]
                  
                  print(list1)
                  

                  【讨论】:

                    【解决方案12】:

                    那些是元组,而不是集合。你可以这样做:

                    l1 = [(1, u'abc'), (2, u'def')]
                    l2 = [(tup[0],) for tup in l1]
                    l2
                    >>> [(1,), (2,)]
                    

                    【讨论】:

                    • 不是真的问什么
                    【解决方案13】:

                    您可以unpack 您的元组并使用列表理解仅获取第一个元素:

                    l = [(1, u'abc'), (2, u'def')]
                    [f for f, *_ in l]
                    

                    输出:

                    [1, 2]
                    

                    无论元组中有多少元素,这都会起作用:

                    l = [(1, u'abc'), (2, u'def', 2, 4, 5, 6, 7)]
                    [f for f, *_ in l]
                    

                    输出:

                    [1, 2]
                    

                    【讨论】:

                      【解决方案14】:

                      我更喜欢这样压缩:

                      >>> lst = [(1, u'abc'), (2, u'def')]
                      >>> new, _ = zip(*lst)
                      >>> new
                      (1, 2)
                      >>> 
                      

                      或者如果你不知道有多少额外的值:

                      >>> new, *_ = zip(*lst)
                      >>> new
                      (1, 2)
                      >>> 
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2019-04-19
                        • 2019-05-20
                        • 1970-01-01
                        • 2016-12-31
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多