Как найти тип массива

Я пытаюсь написать код для преобразования 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 вызывается на каждом символе, тогда как мой подход всегда проверяет первый символ, поэтому может быть немного быстрее.

Другие вопросы по тегам