Reputation: 895
I want to read all lines from a file and store in a list, 2 by 2 elements until list finish iterating.
-Read first 2 lines from a list, and do stuff
-Continue reading more 2 lines, and do stuff
-Do so until whole list finish
Inside test.txt
aa
bb
cc
dd
ee
ff
gg
hh
accounts_list = []
with open('test.txt', 'r') as f:
accounts_list = [line.strip() for line in f]
for acc in accounts_list:
#do stuff with 2
#continue reading more 2
# do another stuff with the next 2
# read until whole list finish
How i can do that, i can't make it.
Upvotes: 0
Views: 67
Reputation: 241881
Here's one reasonably idiomatic way of doing it. The key is the use of zip(it, it)
(passing the same iterator twice), which causes zip
to create a generator of tuples consisting of pairs of values from it
. (A more general form of this idiom is documented under "tips and tricks" in the Python documentation for zip
):
with open('test.txt', 'r') as f:
accounts_iter = (line.strip() for line in f)
for first, second in zip(accounts_iter, accounts_iter):
# Just an example
print(f" First is '{first}'")
print(f"Second is '{second}'")
That snippet does not create a list; it simply iterates over the input. Unless you need to keep the data for later use, there is no point in creating the list; it's simply a waste of memory (which could be a lot of memory if the file is large.) However, if you really wanted a list, for some reason, you could do the following:
with open('test.txt', 'r') as f:
accounts_iter = (line.strip() for line in f)
accounts = [*zip(accounts_iter, accounts_iter)]
That will create a list of tuples, each tuple containing two consecutive lines.
Two other notes:
iter
built-in function (as is done in the example in the Python docs).zip
stops when the shortest iterator finishes. So if your file has an odd number of lines, the above will ignore the last line. If you would prefer to see an error if that happens, you can use the strict=True
keyword argument to zip
(again, as shown in the documentation). If, on the other hand, you'd prefer to have the loop run anyway, even with some missing lines, you could use itertools.zip_longest
instead of zip
.Upvotes: 1
Reputation: 296
To store file in a nested list "2 by 2 elements":
code:
with open('test.txt', 'r') as f:
accounts_list = [[acc0.strip(), acc1.strip()] for acc0, acc1 in zip(f, f)]
output:
[['aa', 'bb'], ['cc', 'dd'], ['ee', 'ff'], ['gg', 'hh']]
then you can iterate over on this list to work with
Upvotes: 1
Reputation: 531938
If you use an explicit iterator (instead of letting the for
loop create its own), you can read two lines per iteration: one by the loop itself, the second in the body.
with open('test.txt', 'r') as f:
itr = iter(f)
for acc1 in itr:
acc2 = next(itr)
# Do stuff with acc1 and acc2
# If the file has an odd number of lines,
# you should wrap the assignment to acc2
# in a try statement to catch the explicit StopIteration it will raise
I don't really like the asymmetry of reading the two lines in two different ways, so I would use an explicit while
loop and use next
to get both lines.
with open('test.txt', 'r') as f:
itr = iter(f)
while True:
try:
acc1 = next(itr)
acc2 = next(itr)
except StopIteration:
break
# Do stuff with acc1 and acc2
Also, be sure to check the recipe section of the itertools
documentation for the grouper
recipe.
Upvotes: 1
Reputation: 4936
I think iterating through the indices by 2 steps range(0, len(accounts_list), 2)
instead of list item of accounts_list
should work
accounts_list = []
with open('test.txt', 'r') as f:
accounts_list = [line.strip() for line in f]
for i in range(0, len(accounts_list), 2):
acc1 = accounts_list[i]
acc2 = accounts_list[i + 1]
#do stuff with 2
#continue reading more 2
# do another stuff with the next 2
# read until whole list finish
Upvotes: 2