1

I have the following list that has been read in from a file: films.txt

    ['0,Genre, Title, Rating, Likes', '1,Sci-Fi,Out of the Silent Planet, PG, 0', '2,Sci-Fi,Solaris, PG,0', '3,Sci-Fi,Star Trek, PG, 0', '4,Sci-Fi,Cosmos, PG, 0', '5,Drama, The English Patient, 15, 0', '6,Drama, Benhur, PG, 0', '7,Drama, The Pursuit of Happiness, 12, 0', '8,Drama, The Thin Red Line, 18, 0', '9,Romance, When Harry met Sally, 12, 0', "10,Romance, You've got mail, 12, 0", '11,Romance, Last Tango in Paris, 18, 0', '12,Romance, Casablanca, 12, 0']

I need to access a specific field (namely the "likes") based on an index number of the film. For instance the output for

  print("PRINT THE CURRENT FILM ROW", allfilms[3])
  print("PRINT THE CURRENT LIKES", allfilms[4])

is:

 PRINT THE CURRENT FILM ROW 3,Sci-Fi,Star Trek, PG, 0
 PRINT THE CURRENT LIKES 4,Sci-Fi,Cosmos, PG, 0

What I want to access however is, the 0, in the third row. That is the 4th field in the third row (or second row), depending on the index number so I'd need an if or loop here.

I tried:

print("PRINT THE CURRENT FILM ROW", allfilms[3][4])

which outputs a character rather than a field....

i

It is reading the "i" character in Sci-fi which is the fourth character along ....

As mentioned, I need the fourth FIELD (the 0). Any thoughts?

Based on the suggestions below, I tried:

def likeafilm(x,username):
#prompt the user to enter the ID number they require
   idnumber=int(input("To confirm, please enter the number of the film you wish to like:"))
   #create a list which stores and displays all the data in the films txt file
   with open("films.txt",mode="r") as f:
      allfilms=[]
      #allfilms=list(csv.reader(allfilms)) - this does not clean the extra spaces so try the next line
      allfilms=[[x.strip() for x in row] for row in csv.reader(allfilms)]
      print(allfilms[3])
      allfilms[3][4]=str(int(allfilms[3][4])+1)
      print(allfilms)

but it produces the following error:

    print(allfilms[3])

IndexError: list index out of range

Also, I need to use an idnumber instead of 3. (as seen in the function above)

print(allfilms[idnumber])

same error:

  print(allfilms[idnumber])
  IndexError: list index out of range

2 Answers2

1

basically, each element of your array is a string. You implicitly decide that the 4th field is the 4th element from a comma-separated list point of view.

All you need is to materialize this split:

print("PRINT THE CURRENT FILM ROW", allfilms[3].split(",")[4])

alternately (and it's lesser known) you could pass your list as-is to a csv.reader object, which splits the strings for you and you can iterate over the splitted rows. I selected some of the fields for the demo:

cr = csv.reader(allfilms)
for row in cr:
    print(row[1],row[2],row[4])

result on your data:

Genre  Title  Likes
Sci-Fi Out of the Silent Planet  0
Sci-Fi Solaris 0
Sci-Fi Star Trek  0
Sci-Fi Cosmos  0
Drama  The English Patient  0
Drama  Benhur  0
Drama  The Pursuit of Happiness  0
Drama  The Thin Red Line  0
Romance  When Harry met Sally  0
Romance  You've got mail  0
Romance  Last Tango in Paris  0
Romance  Casablanca  0

note that it's not the best way of making a database persist, there are unwanted spaces before/after the commas sometimes, I'd recommend to store the items as a list of lists once and for all.

To illustrate this, your follow up question (changing the 0 into 1) would be answered like this:

allfilms[3] = ",".join(["1" if i==4 else x for i,x in enumerate(allfilms[3].split(","))])

(recreate the string, but change 0 by 1 on the 4 index, as you see not very easy)

On the other hand, if you do:

allfilms = list(csv.reader(allfilms))

or with cleaning of the extra spaces:

allfilms = [[x.strip() for x in row] for row in csv.reader(allfilms)]

you get the list of lists. Now:

>>> print(allfilms[3])
['3', 'Sci-Fi', 'Star Trek', 'PG', ' 0']

and to change the index 4 just do:

allfilms[3][4] = '1'

or to "increment", cast to int, add, cast back to string:

allfilms[3][4] = str(int(allfilms[3][4])+1)
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • allfilms[3].split(",")[4]) does produce the '0', thank you. The problem however, is that I need to access it in order to CHANGE its value (increment the value). It isn't just for printing. Do you know what I'd use to change the value from a 0 to +1 (+ 1 to whatever is currently stored in that file) –  Jan 27 '17 at 12:37
  • see my edit. You should change your strategy a little. – Jean-François Fabre Jan 27 '17 at 12:49
  • I've been trying with: currentlikes=allfilms[3].split(",")[4] #this retrieves the current likes from field print(currentlikes) currentlikes=+1 #this increments the current likes stored in the list print(currentlikes) allfilms[3].split(",")[4]=currentlikes #this attempts to change the value from 0 to 1 in the respective field print(allfilms)#this should print the updated list with the incremented +1 in the Third Row, Fourth Field (0 to 1) *will read through your edit, thank you –  Jan 27 '17 at 12:51
  • you cannot directly +=1 on a string. You need to convert to integer first. – Jean-François Fabre Jan 27 '17 at 12:53
  • In the edit above, I have converted the idnumber to integer, but still the same error .... I also tried your method. Thanks for this help and the explanation ...any thoughts? –  Jan 27 '17 at 13:06
0

In Python, indexing is used to access an element inside a string object.

In[] : name = 'pythoncarrot'
In[] : name[3]
Out[]: 'h'  

In order to access a field of a "film" string, you need to mention this explicitly to the Python interpreter. One of the ways to do this is to split the string into fields:

In[] : film = '3,Sci-Fi,Star Trek, PG, 0'
In[] : fields = film.split(',')
In[] : fields
Out[]: ['3', 'Sci-Fi', 'Star Trek', ' PG', ' 0']

The fields object is of the type list. You can access the required field by its index, namely 4 in this case.

In[] : fields[4]
Out[]: '0'

Hence, the final code should be something like this:

all_films = ['0,Genre, Title, Rating, Likes', '1,Sci-Fi,Out of the Silent Planet, PG, 0', '2,Sci-Fi,Solaris, PG,0', '3,Sci-Fi,Star Trek, PG, 0', '4,Sci-Fi,Cosmos, PG, 0', '5,Drama, The English Patient, 15, 0', '6,Drama, Benhur, PG, 0', '7,Drama, The Pursuit of Happiness, 12, 0', '8,Drama, The Thin Red Line, 18, 0', '9,Romance, When Harry met Sally, 12, 0', "10,Romance, You've got mail, 12, 0", '11,Romance, Last Tango in Paris, 18, 0', '12,Romance, Casablanca, 12, 0']

for index, film in enumerate(all_films):
    if index == 3:
        print(film.split(',')[4])

General advice: Storing the data in a list object may not be the best idea (unless you want to mutate it; Immutable vs Mutable types). I would suggest you to either use a list of dict to store the data or implement a class Film to create a list a Film objects. This would help you with quick and easy data querying.

Community
  • 1
  • 1
Kshitij Saraogi
  • 6,821
  • 8
  • 41
  • 71
  • tried this: for index, film in enumerate(allfilms): if index==3: print(film.split(',')[4]) error: print(film.split(',')[4]) IndexError: list index out of range –  Jan 27 '17 at 13:15
  • @pythoncarrot This is working on my console. Are you sure about this ? – Kshitij Saraogi Jan 27 '17 at 13:18
  • yes - I assume the indentation of the print (last line) is important? ....or is it how you have written it –  Jan 27 '17 at 20:12
  • @pythoncarrot In Python, the indentation of every Line is important, even the docstrings. – Kshitij Saraogi Jan 28 '17 at 03:24