2013-04-27 3 views
1

Я хочу преобразовать список строк в их правильные типы (т. Е. 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] 

EDIT:

Я создаю, б, в, г из большого текстового файла и Я надеялся, что есть элегантный способ сделать конверсию на одной линии. Это вопрос не только для этого конкретного примера, но вопрос о модуле, который может сделать что-то вроде этого:

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] 

Основываясь на комментарий Никлас Нильсона, я мог бы сделать следующее:

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

Если бы у вас не было этого поплавка, я бы предложил '[ast.literal_eval (s) для s в strLst]' –

+0

на самом деле это отлично на основе моего редактирования. –

+0

Поплавок, кажется, работает отлично для меня в 2.7? –

ответ

4

проносясь и применение функций литья работает и намного быстрее, чем 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 
+0

КРАСИВЫЙ, теперь это то, о чем я мечтал, было бы доступно, когда я задал этот вопрос. Спасибо! –

+1

Заменил bool() лямбдой, которая возвращает True, если строка == 'True', а в противном случае False. Применение значений bool() к «True» или «False» всегда будет возвращать True, потому что это обе непустые строки. – derek

0

Я знаю, что вопрос слишком стар. Но мой первый вопрос - почему он должен быть однострочным? Я имею в виду, даже если решение принимает 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) 

Даже если вызов функции занимает немного времени (безусловно, в микро секунд), это быстрее и изящнее, чем при использовании молнии.

Заменяя тестовый код derek, я мог видеть 20% уменьшенное время с этой функцией, определяемой пользователем, и 30% уменьшенное время в случае двух лайнеров.

Смежные вопросы