Hick
Hick

Reputation: 36404

What is a better way to readlines from Python file?

This is my python file:-

TestCases-2
Input-5
Output-1,1,2,3,5
Input-7
Ouput-1,1,2,3,5,8,13

What I want is this:-

I've tried doing it in this way:

               testInput = testCase.readline(-10)

        for i in range(0,int(testInput)):
            testCaseInput = testCase.readline(-6)
            testCaseOutput = testCase.readline(-7)

The next step would be to strip the numbers on the basis of (','), and then put them in a list.

Weirdly, the readline(-6) is not giving desired results.

Is there a better way to do this, which obviously I'm missing out on.

I don't mind using serialization here but I want to make it very simple for someone to write a text file as the one I have shown and then take the data out of it. How to do that?

Upvotes: 3

Views: 1831

Answers (4)

Raymond Hettinger
Raymond Hettinger

Reputation: 226336

A negative argument to the readline method specifies the number of bytes to read. I don't think this is what you want to be doing.

Instead, it is simpler to pull everything into a list all at once with readlines():

with open('data.txt') as f:
    full_lines = f.readlines()

# parse full lines to get the text to right of "-"
lines = [line.partition('-')[2].rstrip() for line in full_lines]

numcases = int(lines[0])
for i in range(1, len(lines), 2):
    caseinput = lines[i]
    caseoutput = lines[i+1]
    ...

The idea here is to separate concerns (the source of the data, the parsing of '-', and the business logic of what to do with the cases). That is better than having a readline() and redundant parsing logic at every step.

Upvotes: 2

DhruvPathak
DhruvPathak

Reputation: 43245

  1. This line has an error:

    Ouput-1,1,2,3,5,8,13  // it should be 'Output' not 'Ouput
    
  2. This should work:

    testCase = open('in.txt', 'r')
    testInput = int(testCase.readline().replace("TestCases-",""))
    for i in range(0,int(testInput)):
        testCaseInput = testCase.readline().replace("Input-","")
        testCaseOutput = testCase.readline().replace("Output-","").split(",")
    

Upvotes: 1

Benedict
Benedict

Reputation: 2821

You can use regex for this and it makes it much easier. See question: python: multiline regular expression

For your case, try this:

import re
s = open("input.txt","r").read()
(inputs,outputs) = zip(*re.findall(r"Input-(?P<input>.*)\nOutput-(?P<output>.*)\n",s))

and then split(",") each output element as required

If you do it this way you get the benefit that you don't need the first line in your input file so you don't need to specify how many entries you have in advance.

You can also take away the unzip (that's the zip(*...) ) from the code above, and then you can deal with each input and output a pair at a time. My guess is that is in fact exactly what you are trying to do.

EDIT Wanted to give you the full example of what I meant just then. I'm assuming this is for a testing script so I would say use the power of the pattern matching iterator to help keep your code shorter and simpler:

for (input,output) in re.findall(r"Input-(?P<input>.*)\nOutput-(?P<output>.*)\n",s):
  expectedResults = output.split(",")

  testResults = runTest(input)
  // compare testResults and expectedResults ...

Upvotes: 1

Oliver
Oliver

Reputation: 11607

I'm not sure if I follow exactly what you're trying to do, but I guess I'd try something like this:

testCaseIn = [];
testCaseOut = [];

for line in testInput:
    if (line.startsWith("Input")):
        testCaseIn.append(giveMeAList(line.split("-")[1]));
    elif (line.startsWith("Output")):
        testCaseOut.append(giveMeAList(line.split("-")[1]));

where giveMeAList() is a function that takes a comma seperated list of numbers, and generates a list datathing from it.

I didn't test this code, but I've written stuff that uses this kind of structure when I've wanted to make configuration files in the past.

Upvotes: 2

Related Questions