【问题标题】:Convert list of strings into multiple data types in one line在一行中将字符串列表转换为多种数据类型
【发布时间】:2013-04-27 20:36:34
【问题描述】:

我想在一行中将字符串列表转换为正确的类型(即 int、float、boolean 等)并解压缩这些值。

是否有内置模块可以比以下更好地完成此任务?:

strLst = ["a", "1.0", "2", "True"]
a, b, c, d = [[s[0], float(s[1]), int(s[2]), bool(s[3])] for s in [strLst]][0]

编辑:

我正在从一个大文本文件创建 a、b、c、d,我希望有一种优雅的方法可以在一行上进行转换。这不仅仅是针对这个特定示例的问题,而是关于可以完成类似操作的模块的问题:

with open("file.txt") as f:
    a, b, c, d = [[s[0], float(s[1]), int(s[2]), bool(s[3])] \
                       for s in [next(f)[:-1].split()]][0]

根据 Niclas Nilsson 的评论,我可以执行以下操作:

a,b,c,d = [ast.literal_eval(s) for s in next(f)[:-1].split()]

【问题讨论】:

  • 如果你没有那个浮动,我建议[ast.literal_eval(s) for s in strLst]
  • 实际上,根据我的编辑,这是完美的。
  • float 在 2.7 中对我来说似乎工作正常?
  • 为什么需要一行完成?它似乎相当非pythony,因为您提出的任何解决方案都不太可能生成非常易读的代码。
  • 我觉得基于我试图完成的工作,会有一个模块可以用一种非常紧凑和简洁的方式来表达这一点。正如 Niclas 上面指出的,事实证明这是真的(61 个字符)。这不是简洁和Pythonic吗?

标签: python string type-conversion


【解决方案1】:

压缩和应用转换函数有效,并且比literal_eval快得多。

此外,如果字符串值不包含引号,literal_eval 会引发“ValueError: malformed string”,根据您的数据,这可能会出现问题。

from StringIO import StringIO
from time import time
import ast

def zip_test():
    # Using StringIO to illustrate using something file-like.                   
    for row in StringIO('a 1.0 2 True\n' * 32):
        (a, b, c, d) = [f(v) for (f, v) in zip(
                (str, float, int, lambda v: v == 'True'), row.split())]

def ast_test():
    for row in StringIO('"a" 1.0 2 True\n' * 32):
        (a, b, c, d) = [ast.literal_eval(s) for s in row.split()]

for f in (zip_test, ast_test):
    start = time()
    for i in range(100):
        f()
    print '%s: %s' % (f.func_name, time() - start)


 # [ ** Results ** ]
 #
 # zip_test: 0.0131301879883
 # ast_test: 0.0835828781128

【讨论】:

  • 美丽,当我问这个问题时,这就是我梦寐以求的。谢谢!
  • 将 bool() 替换为 lambda,如果 string == 'True' 则返回 True,否则返回 False。将 bool() 应用于“True”或“False”字符串值将始终返回 True,因为它们都是非空字符串。
【解决方案2】:

我知道这个问题太老了。但我的第一个问题是为什么它必须是单线的?我的意思是,即使解决方案需要 100 行,您也可以随时将它们放在一个函数下并在其他任何地方调用该函数,这样解决方案将是单行的,对吗?

如果需要速度的话,我确实想出了一个比建议更快、更简单的双线。

for row in StringIO('a 1.0 2 True\n' * 32):# Took the idea from derek's answer
    (a, b, c, d) = row.split(" ", 3)
    b, c, d = float(b), int(c), 'True' in d

正如我所提到的,如果无法使用它并且您肯定需要单线,您可以随时执行以下操作:

def string_to_multiple_type_list(data):
    multi_list = []
    for line in data.split("\n"):
        a, b, c, d = line.split(" ", 3)
        multi_list.append([a, float(b), int(c), 'True' in d])
    return multi_list

并且每当您需要转换后的值时,都可以将其称为单线:

new_multi_list = string_to_multiple_type_list(data)

尽管函数调用需要一点时间(绝对以微秒为单位),但它比使用 zip 更快、更优雅。

借用 derek 的测试代码,我可以看到使用这个用户定义的函数可以减少 20% 的时间,如果使用两个班轮,可以减少 30% 的时间。

【讨论】:

    猜你喜欢
    • 2011-12-07
    • 2018-12-24
    • 2016-11-14
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 2023-01-04
    相关资源
    最近更新 更多