Как найти тип массива
Я пытаюсь написать код для преобразования CSV в ARFF. Я импортирую значения между каждым ","
в ячейку массива, например, такой как:
Monday,176,49,203,27,77,38,Second
преобразуется в:
['Monday', '176', '49', '203', '27', '77', '38', 'Second']
Проблема в том, что Python распознает каждую ячейку как строку, и вы можете увидеть распознанные типы Python для примера:
[<type 'str'>, <type 'str'>, <type 'str'>, <type 'str'>, <type 'str'>, <type 'str'>, <type 'str'>, <type 'str'>]
Я ищу способ разграничить номинальные и числовые атрибуты?
3 ответа
Лучшее, что я могу придумать, это что-то вроде этого, используя ast.literal_eval:
import ast
def converter(x):
try:
val = ast.literal_eval(x)
return val
except ValueError:
return x
который дает
>>> seq = ['Monday', '176', '49', '203', '27', '77', '38', 'Second']
>>> newseq = [converter(x) for x in seq]
>>> newseq
['Monday', 176, 49, 203, 27, 77, 38, 'Second']
>>> map(type, newseq)
[<type 'str'>, <type 'int'>, <type 'int'>, <type 'int'>, <type 'int'>, <type 'int'>, <type 'int'>, <type 'str'>]
Преимущество использования ast.literal_eval
в том, что он хорошо обрабатывает больше дел:
>>> seq = ['Monday', '12.3', '(1, 2.3)', '[2,"fred"]']
>>> newseq = [converter(x) for x in seq]
>>> newseq
['Monday', 12.3, (1, 2.3), [2, 'fred']]
for i in lst:
try:
int(i)
#whatever you want to do
except ValueError:
#error handling
Это будет работать, хотя от этого было бы намного лучше:
for i in lst:
if i[-1].isdigit(): #it is a number
#whatever
else:
#whatever else
Взято отсюда
Смотрите также: метод str.isdigit()
Если производительность здесь имеет большое значение, я постараюсь принять трехэтапный подход. Такой подход без необходимости избегает забрасывания строки в int
или же float
а затем не удается, используя простую проверку для первого символа.
- Для каждого чанка проверьте, является ли первый символ цифрой или нет
- Если это так, сначала попробуйте разобрать его как
int
и если это не удается, разобрать его какfloat
- Если все это терпит неудачу, у вас есть большие проблемы:)
Что-то вроде:
for chunk in chunks:
if chunk[0].isdigit():
try:
return int(chunk)
except ValueError:
return float(chunk)
else:
# It's a string (a non-numeric entity)
return chunk
Вам, конечно, понадобится немного больше специальной обработки для поддержки литералов hex/oct в файле text/csv, но я не думаю, что это нормально для вас?
РЕДАКТИРОВАТЬ: Если подумать, волатильность использовала аналогичный подход с единственной разницей в том, чтобы звонить isdigit
на всю строку вместо только первого символа. Это может занять немного больше времени, если у нас есть длинные числовые последовательности, в которых isdigit
вызывается на каждом символе, тогда как мой подход всегда проверяет первый символ, поэтому может быть немного быстрее.