Question

I have a textfile as below and I want to either yield the odd/even lines:

this is a blah 
 I don't care,
whatever foo bar
ahaha

I have tried checking for the odd/even-ness of the enumerate index but what is the pythonic way to do yield alternate lines in a textfile? I've tried:

text = "this is a blah \n I don't care,\nwhatever foo bar\nahaha"
with open('test.txt', 'w') as fout:
    for i in text.split('\n'):
        print>>fout, i

def yield_alt(infile, option='odd'):
    with open(infile,'r') as fin:
        for i,j in enumerate(fin):
            if option=='odd':
                if i+1 & 0x1:
                    yield j
            elif option=='even':
                if i & 0x1:
                    yield j

for i in yield_alt('test.txt'):
    print i

[out]:

this is a blah 

whatever foo bar

Lastly, what does i & 0x1 mean? I know it checks for even int, is there other ways of checking for even integers?

Was it helpful?

Solution

Another way to do this is to use iterools.islice to slice the file object:

>>> from itertools import islice
>>> def yield_alt(f, option='odd'):
        if option == 'odd':
            return islice(f, 0, None, 2)
        return islice(f, 1, None, 2)
... 
>>> with open('abc1') as f:
    for line in yield_alt(f):      
        print line,
...         
this is a blah 
whatever foo bar

>>> with open('abc1') as f:
    for line in yield_alt(f, 'even'):
        print line,
...         
 I don't care,
ahaha

OTHER TIPS

i & 0x1 is bitmasking the last bit, to check if i is even or odd. I generally do i % 2 because it feels clearer to me, but not sure which one has better performance.


Edit: timeit and dis:

>>> timeit(lambda:5 & 0x1, number=1000000)
0.10139431793770104

>>> timeit(lambda:5 % 2, number=1000000)
0.10143369172932282

>>> dis.dis(lambda: 5 & 0x1)
  1           0 LOAD_CONST               2 (1)
              3 RETURN_VALUE

>>> dis.dis(lambda: 5 % 2)
  1           0 LOAD_CONST               2 (1)
              3 RETURN_VALUE

They are almost exactly identical. Whichever is clearer to you is the one you should use.

islice is probably your best choice, but for completeness I'll add another option using next to skip the lines you don't want.

def yield_alt(filename, option='odd'):
    with open(filename) as ifile:
        if option.lower() == 'odd':
            # Skip first line
            next(ifile)
        for line in ifile:
            yield line
            # Skip next line
            next(ifile)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top