每行乘以2个元素,创建新列,列表列表 - python

时间:2014-08-21 02:00:52

标签: python arrays list multidimensional-array

我有一份清单清单:

mylist = [['Bob','AA',3,2.1,4],['Sally','BB',2,5.1,3],['Jim','CC',2,1.5,4]]

我需要将元素2和3相乘并将得到的解决方案插入到索引4中,将所有内容移到一起并格式化浮点错误。期望的输出:

mylist = [['Bob','AA',3,2.1,6.3,4],['Sally','BB',2,5.1,10.2,3],['Jim','CC',2,1.5,3,4]]

我几乎用以下方法解决了这个问题:

for i, val in enumerate(mylist):
    sol = (float(val[2]*val[3]))
    val.insert(4,'%.3f' % sol)

print(mylist)

我得到了:

[['Bob', 'AA', 3, 2.1, 6.300, 4], ['Sally', 'BB', 2, 5.1, 10.200, 3], ['Jim', 'CC', 2, 1.5, 3.000, 4]]

2个问题:

  1. 是否有比我目前的解决方案更加pythonic的方式? (列表理解会很好)
  2. 如何正确格式化浮点错误? (编辑:插入时包含'%。3f'%,似乎工作正常。)

2 个答案:

答案 0 :(得分:1)

  

是否有比我目前的解决方案更加pythonic的方式? (列表理解会很好)

列表理解是一种构建列表的Pythonic方法。将副作用应用于一堆值不是Pythonic方法。 Pythonic的方法是使用for语句,就像你做的一样。

您的代码没有什么问题,但是,与大多数代码一样,它可以得到改进:

  • 如果您不需要enumerate值,请不要使用i;只是循环遍历列表本身。
  • 请勿将值转换为保证已为float值的float
  • 不要在整个表达式周围添加额外的表达,除非它们在某种程度上对可读性有用。
  • 为了格式化单个值,format函数通常比str.format%更简单,更易读(也可能更有效,但不太重要)。
  • 如果可行,标识符应使用完整的英文单词,标准技术缩写除外。
  • 当乘以两个复合表达式时,它周围的空格可以说更清晰 *(虽然此处value[2]位于边线处。)

所以:

for value in mylist:
    solution = value[2] * value[3]
    value.insert(4, format(solution, '.3'))

PEP 8就其中的一些问题提供了一些指导,但并不多。


同时,大概这些元素具有一些固有的含义。我不知道它们代表什么,但将它们解压缩到命名变量而不是仅使用索引可能更好:

    name, thingy, count, weight, stuffness = value
    solution = count * weight

或者:

    _, _, count, weight, _ = value
    solution = count * weight

另外,鉴于这些东西是固定形状的异构集合,最好将它们存储为元组而不是列表。当然,你正在做的是改变列表,所以这不适用于此。但也许你不应该在第一时间做到这一点。也许最好建立一个新的元组列表。在这种情况下,你实际上可以使用列表理解:

[value + (format(value[2] * value[3], '.3'),) for value in mylist]

......或者,结合最后两个想法:

[(name, thingy, count, weight, stuffness, format(count * weight, '.3'))
 for (name, thingy, count, weight, stiffness) in mylist]

这实际上是否更具可读性或更多pythonic是非常有争议的。

答案 1 :(得分:-1)

  
      
  1. 是否有比我目前的解决方案更加pythonic的方式? (列表理解会很好)
  2.   

您使用for循环的方法是正确的,非常" pythonic。"这里只是一个小小的注释:

  • 如果您未在代码中使用索引enumerate(),则不必使用i

也就是说,如果您有兴趣考虑其他特定于python的替代方案,也可以使用list comprehension。有两种方法:

使用运算符重载的列表理解:

您还可以通过重载+运算符来使用列表并置。如果你放松新产品进入第四个索引的条件,而不是将输出放在列表的末尾,那么解决方案会更优雅。因此,我们可以用一个列表理解来替换for循环:

myList = [ val + [float( format( val[2]*val[3], '.3f'))] for val in myList ]

这将给我们:

>>> print(myList)
[['Bob', 'AA', 3, 2.1, 4, 6.3], ['Sally', 'BB', 2, 5.1, 3, 10.2], ['Jim', 'CC', 2, 1.5, 4, 3.0]]

您仍然可以使用稍微不那么优雅的配方实现将产品放入第4个指数所需的输出:

myList = [ val[:3] + [float( format( val[2]*val[3], '.3f'))] + val[4:] for val in myList ]

insert()列表理解:

insert()函数的工作方式略有不同,所以要小心谨慎。 insert()在列表推导中使用时,会修改原始列表。因此,您不需要将列表推导分配给新变量。

考虑到这一点,您可以将for循环替换为:

[ val.insert( 4, float( format( val[2] * val[3], '.3f') ) for val in myList ];

这将正确更新您的myList变量,并像以前一样提供给我们:

>>> print(myList)
[['Bob', 'AA', 3, 2.1, 6.3, 4], ['Sally', 'BB', 2, 5.1, 10.2, 3], ['Jim', 'CC', 2, 1.5, 3.0, 4]]

使用insert()函数列表理解的注意事项:

  1. 分号,;,在列表理解的末尾需要抑制不必要的输出,否则会导致显示[None, None, None]
  2. 在这种情况下,可能不建议使用列表推导,因为它使解决方案的可读性降低,并通过构建从未使用过的列表来浪费内存资源。
  3. 2. How do I correctly format the float errors? (EDIT: Included '%.3f' % at the insert, seems to work ok.)
    

    正如您在上面所看到的,format()功能在这里效果最好。

    关于浮点精度的注释:

    1. 使用format()函数为数字分配适当的浮点精度,然后将结果字符串转换为float(),然后适当地剥离尾随的无关零。
    2. 由于您在此处评估产品,因此您不需要将其中一个元素或产品本身投射为float(),因为在乘法过程中您不会失去任何精度。但是,如果要划分2个列表元素,则必须进行强制转换。在这种情况下,必须首先将除数或被除数转换为float( val[2] )以确保浮点除法,否则将导致整数除法。