Charles Wallace
Charles Wallace

Reputation: 23

Find an replace list value based on other list values

I am working on an assignment for school and have hit a wall.

The challenge is:

You will be passed the filename P, firstname F, lastname L, and a new birthday B.

Load the fixed length record file in P, search for F,L in the first and change birthday to B.

Then save the file.


I have managed to read from the file and split the data into the desired entries in a list.
However, my issue arises when I am searching for the first and last name in the list.
The first and last name being passed is Adam Smith, but there is also an Adam Smithers in the list who is found by my code as well. When I attempt to replace the desired element of the list, it is replacing it for both Smith and Smithers.

We cannot use regular expressions for the assignment, so I am at a bit of a loss for how to approach this and find an exact match for the last name while ignoring the other last name that contains Smith without using regex.

Here's my code:

import sys

P= sys.argv[1] 
F= sys.argv[2]
L= sys.argv[3]
B= sys.argv[4]

filePath = P
firstName = F
lastName = L
newBirthday = B
records = []

file1 = open(filePath, 'r')
fileContent = file1.read()

while len(fileContent) > 0:
  record = []
  fname = fileContent[0:16]
  lname = fileContent[16:32]
  bday = fileContent[32:40]
  record = [fname,lname,bday]
  records.append(record)
  fileContent = fileContent[40:]

for record in records:
  if firstName in record[0] and lastName in record[1]:
    record[2] = newBirthday

file1.close()

file2 = open(filePath, 'w')

for record in records:
  file2.write(record[0])
  file2.write(record[1])
  file2.write(record[2])

file2.close()

Any ideas or hints that someone would be able to provide will be most appreciated.

Thanks!

Edit:

Icewine was kind enough to suggest using the below instead:

if firstName == record[0] and lastName == record[1]:

However, when I try that, it does not find any matching records.

I believe this is because there as blank spaces after each name to make up 16 characters in each name, giving a fixed length for the name. So when I'm using the == operator, it's not finding an exact match because there are also blank spaces in the name, so it's not an exact match.

Upvotes: 2

Views: 327

Answers (5)

Ralf
Ralf

Reputation: 16495

Here are a few improvements I could suggest to your code:

  • make a function or at least put the code inside if __name__ == '__main__':. You can google why.
  • I suggest using with open(file_path, 'r') as f: to read and write files; it looks cleaner and you won't forget to close the file.
  • remove surounding spaces before comparing to your input; I used line[:16].strip().
  • you read in specified widths, so don't forget to write back into the file with those same widths. This code ensures that each part of the record has the specified width:

    f.write('{:16s}{:16s}{:8s}'.format(*record))
    

Here is my version of the code:

import sys

if __name__ == '__main__':
    file_path = sys.argv[1]
    first_name = sys.argv[2]
    last_name = sys.argv[3]
    new_birth_date = sys.argv[4]

    record_list = []

    with open(file_path, 'r') as f:
        while True:
            line = f.read(40)               # read 40 chars at the time
            if len(line) == 0:
                # the end of the file was reached
                break

            record = [
                line[:16].strip(),
                line[16:32].strip(),
                line[32:].strip(),
            ]
            if first_name == record[0] and last_name == record[1]:
                record[2] = new_birth_date

            record_list.append(record)

    with open(file_path, 'w') as f:
        for record in record_list:
            f.write('{:16s}{:16s}{:8s}'.format(*record))

Does this work for you?


Note: this code does not split lines by newlines, but it reads 40 chars at the time, so you could end up with a newline char inside those 40 chars.

I did it this way because the code in the question seems to do something similar.

Upvotes: 0

Param Kapur
Param Kapur

Reputation: 389

An easy solution to this would be to sort the list of names and values (in this case, birthdays (I suggest you use a dictionary for this purpose) and then perform a search operation that finds only the first occurrence of an element. That way only Adam Smith is selected.

You can then further deal with duplicates by checking if the next element is the same as the one you found.

i.e. if the first occurrence is i, check if i+1 == i, and update all of the duplicates. (this may be what you need to do for your exercise, though it doesn't make sense to update other people's birthdays like this.)

Hopefully this helps :)

Upvotes: 0

TigerhawkT3
TigerhawkT3

Reputation: 49320

Either pad spaces onto the passed data to match what's in the file:

firstName = f'{F:<16}'

or strip the extra spaces from the file contents to match the passed data:

fname = fileContent[0:16].strip()

then you can simply compare the names, either keeping the in operator or using ==.

Upvotes: 1

Akhil Mohan
Akhil Mohan

Reputation: 105

Trim the whitespaces in the string and then use == for matching. This will give the expected output. Sample code

for record in records:
  if firstName == record[0].strip() and lastName == record[1].strip():
    record[2] = newBirthday

Upvotes: 1

Icewine
Icewine

Reputation: 1851

Use == instead of in

 if firstName == record[0] and lastName == record[1]:

EDIT: try this

Removes whitespace from end of string

 if firstName.rstrip() == record[0].rstrip() and lastName.rstrip() == record[1].rstrip()

or

Removes whitespace from start and end of string

 if firstName.strip() == record[0].strip() and lastName.strip() == record[1].strip()

Upvotes: 1

Related Questions