Although the solution presented may generate the expected result, it is far from being idiomatic, although I believe it was useful to compare with the code presented in the question and help identify the errors. I therefore propose a slightly more elegant solution for the language in question:
with open("numbers_1.txt") as numbers_1, open("numbers_2.txt") as numbers_2:
for pair in zip(numbers_1, numbers_2):
print(sum(map(int, pair)))
See working on Repl.it
With the with
open both files in read mode, instantiating the two generators responsible for each file, numbers_1
and numbers_2
, respectively. After, itero with a loop for
on the outcome of zip()
, which makes the association between the elements of the two generators: the nth term of numbers_1
is associated with the nth term of numbers_2
in a tuple, where n varies from 0 to the length of the sequence (minus one). Then display the sum result, through the function sum()
, which receives an iterable which is responsible for converting the values of the pair into integer values.
In a way, the code can still be improved by building a generator from this structure:
def sum_of_files(file_1, file_2):
with open(file_1) as numbers_1, open(file_2) as numbers_2:
for pair in zip(numbers_1, numbers_2):
yield sum(map(int, pair))
for s in sum_of_files('numbers_1.txt', 'numbers_2.txt'):
print(s)
See working on Repl.it
The advantage of this second solution is that you do not need to, at any time, keep the sequence of values stored completely in memory, which greatly optimizes if your files grow spontaneously, and can reach thousands of lines or more. The first solution would have the final sequence stored in the memory (considering that the print
) and the solution of the other answer would have three times the stored sequence (demand much more resources).
It is even possible to improve the code by breaking the limitation of only two files, allowing as many files are needed:
def sum_of_files(*files):
streams = map(open, files)
for numbers in zip(*streams):
yield sum(map(int, numbers))
for stream in streams:
stream.close()
for s in sum_of_files('numbers_1.txt', 'numbers_2.txt', 'numbers_3.txt'):
print(s)
See working on Repl.it
And yet it is possible to improve by breaking the limitation that files need to be of the same size by overwriting the function zip()
by function itertools.zip_longest()
:
from itertools import zip_longest
def sum_of_files(*files):
streams = map(open, files)
for numbers in zip_longest(*streams, fillvalue=0):
yield sum(map(int, numbers))
for stream in streams:
stream.close()
for s in sum_of_files('numbers_1.txt', 'numbers_2.txt', 'numbers_3.txt'):
print(s)
See working on Repl.it
Smaller files, which do not have the full sequence of values, will have their numbers equal to 0 due to the parameter fillvalue
. This way, you will be able to sum up as many files as necessary, regardless of the size of each one, as long as they have valid values, without having to store the sequence in memory, and the code is very efficient even for files with millions of lines.
Thanks for the help. ^^
– Jeferson S