Irinel Iovan
Irinel Iovan

Reputation: 895

Read lines 2by 2 python

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

Answers (4)

rici
rici

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:

  1. This only works with iterators (which includes generators); not with iterable containers. You need to turn an iterable container into an iterator using the iter built-in function (as is done in the example in the Python docs).
  2. 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

Norbert Tiborcz
Norbert Tiborcz

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

chepner
chepner

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

vht981230
vht981230

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

Related Questions