Эффективный способ чтения целых чисел из файла
Я хотел бы прочитать все целые числа из файла в один список. Все номера разделяются пробелом (одним или несколькими) или символом конца строки (один или несколько). Каков наиболее эффективный и/или элегантный способ сделать это? У меня есть два решения, но я не знаю, хороши они или нет.
-
Проверка цифр:
for line in open("foo.txt", "r"):
for i in line.strip().split(' '):
if i.isdigit():
my_list.append(int(i))
-
Работа с исключениями:
for line in open("foo.txt", "r"):
for i in line:
try:
my_list.append(int(i))
except ValueError:
pass
Пример данных:
1 2 3
4 56
789
9 91 56
10
11
Ответы
Ответ 1
Эффективным способом сделать это будет ваш первый метод с небольшим изменением использования инструкции with
для открытия файла, пример -
with open("foo.txt", "r") as f:
for line in f:
for i in line.split():
if i.isdigit():
my_list.append(int(i))
Сроки выполнения тестов с использованием других методов -
Функции -
def func1():
my_list = []
for line in open("foo.txt", "r"):
for i in line.strip().split(' '):
if i.isdigit():
my_list.append(int(i))
return my_list
def func1_1():
return [int(i) for line in open("foo.txt", "r") for i in line.strip().split(' ') if i.isdigit()]
def func1_3():
my_list = []
with open("foo.txt", "r") as f:
for line in f:
for i in line.split():
if i.isdigit():
my_list.append(int(i))
return my_list
def func2():
my_list = []
for line in open("foo.txt", "r"):
for i in line.split():
try:
my_list.append(int(i))
except ValueError:
pass
return my_list
def func3():
my_list = []
with open("foo.txt","r") as f:
cf = csv.reader(f, delimiter=' ')
for row in cf:
my_list.extend([int(i) for i in row if i.isdigit()])
return my_list
Результаты тестов времени -
In [25]: timeit func1()
The slowest run took 4.70 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 204 µs per loop
In [26]: timeit func1_1()
The slowest run took 4.39 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 207 µs per loop
In [27]: timeit func1_3()
The slowest run took 5.46 times longer than the fastest. This could mean that an intermediate result is being cached
10000 loops, best of 3: 191 µs per loop
In [28]: timeit func2()
The slowest run took 4.09 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 212 µs per loop
In [34]: timeit func3()
The slowest run took 4.38 times longer than the fastest. This could mean that an intermediate result is being cached
10000 loops, best of 3: 202 µs per loop
Учитывая методы, которые хранят данные в списке, я считаю, что func1_3()
выше быстрее (как показано в timeit).
Но учитывая, что если вы действительно обрабатываете очень большие файлы, вам может быть лучше использовать генератор, а не хранить полный список в памяти.
ОБНОВЛЕНИЕ. Как было сказано в комментариях, func2()
быстрее, чем func1_3()
(хотя в моей системе он никогда не был быстрее, чем func1_3()
даже для целых чисел), обновлялся foo.txt
содержать вещи, отличные от чисел, и принимать временные тесты -
foo.txt
1 2 10 11
asd dd
dds asda
22 44 32 11 23
dd dsa dds
21 12
12
33
45
dds
asdas
dasdasd dasd das d asda sda
Тест -
In [13]: %timeit func1_3()
The slowest run took 6.17 times longer than the fastest. This could mean that an intermediate result is being cached
1000 loops, best of 3: 210 µs per loop
In [14]: %timeit func2()
1000 loops, best of 3: 279 µs per loop
In [15]: %timeit func1_3()
1000 loops, best of 3: 213 µs per loop
In [16]: %timeit func2()
1000 loops, best of 3: 273 µs per loop
Ответ 2
Это довольно легко, если вы можете прочитать весь файл в виде строки. (т.е. он не слишком большой для этого)
fileStr = open('foo.txt').read().split()
integers = [int(x) for x in fileStr if x.isdigit()]
read()
превращает его в длинную строку, а split
разделяется на список строк на основе пробелов (т.е. пробелы и символы новой строки). Таким образом, вы можете комбинировать это со списком, который преобразует их в целые числа, если они являются цифрами.
Как отметил Бакуриу, если в файле гарантированы только пробелы и цифры, то вам не нужно проверять isdigit(). Использовать list(map(int, open('foo.txt').read().split()))
было бы достаточно в этом случае. Этот метод будет вызывать ошибки, если что-либо является недопустимым целым числом, тогда как другое будет пропускать все, что не является признанной цифрой.
Ответ 3
Спасибо всем. Я смешал некоторые решения, которые вы опубликовали. Мне это кажется очень хорошим:
with open("foo.txt","r") as f:
my_list = [int(i) for line in f for i in line.split() if i.isdigit()]
Ответ 4
Вы можете сделать это так, используя понимание списка
my_list = [int(i) for j in open("1.txt","r") for i in j.strip().split(" ") if i.isdigit()]
Или with open() method
:
with open("1.txt","r") as f:
my_list = [int(i) for j in f for i in j.strip().split(" ") if i.isdigit()]
процесс:
1. Сначала вы будете выполнять итерацию по строке
2. Затем вы будете итерировать слова и увидеть их цифрами, если мы добавим их в список
изменить
Вам нужно добавить strip()
в строку, потому что каждый конец строки (кроме последней строки) будет иметь новое пространство строк ( "\n" ) в них, и вы пытаетесь is.digit("number\n") you will get false
т.е.)
>>> "1\n".isdigit()
False
edit2:
Ввод:
1
qw 2
23 we 32
Данные файла при чтении:
a=open("1.txt","r")
repr(a.read())
"'1\\nqw 2\\n23 we 32'"
Вы можете увидеть новую строку "\n"
, это повлияет на процесс
Когда я запускаю функцию без strip()
, она не примет 1 and 2
как цифру, потому что она состоит из новых символов строки
my_list = [int(i) for j in open("1.txt","r") for i in j.split(" ") if i.isdigit()]
my_list
[23, 32]
Из вывода видно, что 1 и 2 отсутствуют. Этого можно избежать, если мы использовали strip()
Ответ 5
почему бы не использовать ключевое слово yield
? код будет выглядеть как...
def readInt():
for line in open("foo.txt", "r"):
for i in line.strip().split(' '):
if i.isdigit():
yield int(i)
то вы можете прочитать
for num in readInt():
list.append(num)
Ответ 6
my_list = []
with open('foo.txt') as f:
for line in f:
for s in line.split():
try:
my_list.append(int(s))
except ValueError:
pass
Ответ 7
Попробуйте следующее:
with open('file.txt') as f:
nums = []
for l in f:
l = l.strip()
nums.extend([int(i) for i in l.split() if i.isdigit() and l])
l.strip()
требуется выше, если присутствуют символы новой строки ('\n'), поскольку i.isdigit('6\n')
не будет работать.
list.extend пригодится здесь
and l
в конце обязательно удаляет любой пустой результат списка
str.split по умолчанию разделяет пробелы. А блок with автоматически закроет файл после выполнения кода внутри.
Я также использовал список понятий
Ответ 8
Это был самый быстрый способ, который я нашел:
import re
regex = re.compile(r"\D+")
with open("foo.txt", "r") as f:
my_list = list(map(int, regex.split(f.read())))
Хотя результаты могут зависеть от размера файла.