2

There is a list containing the "Tolkien book"s, and another containing the "Lord of the rings" books.

Some of the books in the "Lord of the rings" books are the same as in the "Tolkien books".

I want to use a for loop to check for which books in the "Tolkien" books are the same as the ones in the "Lord of the rings" books. And if the for loop finds a match, it will change the item in the Tolkien list to "LOTR book: {Tolkien book}"

My issue is: The for loop dosent change the items in the Tolkien list. I know that it rechongnizes the matches, but it dosent change the list. Why is that?

Lord_Of_The_Rings = ["The Hobbit", "The Fellowship of the Ring", "The Two Towers", \
"The Return of the King"]

Tolkien_books = ["The Hobbit", "Farmer Giles of Ham", "The Fellowship of the Ring", \
"The Two Towers", "The Return of the King", "The Adventures of Tom Bombadil", "Tree and Leaf"]



for T_book in Tolkien_books:
    for LOTR_book in Lord_Of_The_Rings:

        if LOTR_book == T_book:
            T_book = f"LOTR: {T_book}"

print(Tolkien_books)
Bill
  • 10,323
  • 10
  • 62
  • 85
Dolphin
  • 11
  • 3
  • `T_book =` doesn't change the object `T_book` was referencing, it changes `T_book` to reference a different object. – Peter Wood Sep 10 '21 at 14:11

5 Answers5

2

This is a fundamental of how python name binding works. I'm going to draw some pictures because it's just so much easier to understand that way.

Binding an object to a name creates a reference. You start out with two names, Lord_Of_The_Rings and Tolkein_Books, which refer to lists. The list elements refer some strings. Notice that the strings are not bound to names, but can be accessed using indexing on the lists:

enter image description here

In the loop for T_book in Tolkien_books:, each successive element of the second list gets assigned to the name T_book. The first iteration looks like this:

enter image description here

If that matches an element in Lord_Of_The_Rings, which 'The Hobbit' does, you do T_book = f"LOTR: {T_book}". That means that you bind a new string object to the name T_book, like this:

enter image description here

Your goal, however, is to update the first element of the list Tolkein_books, which we name Tolkein_books[0]. So you need to switch the assignment T_book = f"LOTR: {T_book}" to Tolkein_books[0] = f"LOTR: {T_book}":

enter image description here

Notice that the name T_book will still refer to the original "The Hobbit" string object that was once in Tolkein_books[0]. Multiple names can refer to the same object.

In practice, to refer to a list item by index, you will need to iterate over an index. You could use the enumerate built-in to iterate over both string and index.

You also don't need to have a nested loop. The in operator hides that for you in list.__contains__. You can iterate over the indices of the list you want to change and update as you go:

for i, name in enumerate(Tolkien_Books):
    if name in Lord_Of_The_Rings:
        Tolkein_Books[i] = f'LOTR: {name}'

You can also discard the original Tolkein_books list and replace it with an updated version that contains the strings you want:

Tolkein_Books = [f'LOTR: {name}' if name in Lord_Of_The_Rings else name for name in Tolkien_Books]
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
0

This is because you are only changing the variable T_Book and not the actual element inside the list.

for index1, T_Book in enumerate(Tolkien_books):
    for index2, LOTR_book in enumerate(Lord_Of_The_Rings):
        if LOTR_book == T_book:
            Tolkien_books[index1] = f"LOTR: {T_book}"
Tugay
  • 2,057
  • 5
  • 17
  • 32
0

You are changing the value of variable T_book, not the element of the list, you can try this:

Lord_Of_The_Rings = ["The Hobbit", "The Fellowship of the Ring", "The Two Towers", "The Return of the King"]

Tolkien_books = ["The Hobbit", "Farmer Giles of Ham", "The Fellowship of the Ring", "The Two Towers", "The Return of the King", "The Adventures of Tom Bombadil", "Tree and Leaf"]



for i, T_book in enumerate(Tolkien_books):
    for LOTR_book in Lord_Of_The_Rings:

        if LOTR_book == T_book:
            Tolkien_books[i] = f"LOTR: {T_book}"

print(Tolkien_books)
Tugay
  • 2,057
  • 5
  • 17
  • 32
0

You are changing the for loop variable T_book which does not reference the same object as that in the Tolkien_books list.

Instead you can do:

Lord_Of_The_Rings = ["The Hobbit", "The Fellowship of the Ring", "The Two Towers",
"The Return of the King"]

Tolkien_books = ["The Hobbit", "Farmer Giles of Ham", "The Fellowship of the Ring",
"The Two Towers", "The Return of the King", "The Adventures of Tom Bombadil", "Tree and Leaf"]

Tolkien_books = [f'LOTR: {book}' if book in Lord_Of_The_Rings else book for book in Tolkien_books]

Which returns:

['LOTR: The Hobbit', 'Farmer Giles of Ham', 'LOTR: The Fellowship of the Ring', 'LOTR: The Two Towers', 'LOTR: The Return of the King', 'The Adventures of Tom Bombadil', 'Tree and Leaf']
ChrisOram
  • 1,254
  • 1
  • 5
  • 17
-2

Use list comprehension to filter the two lists then recombined. (I know I didn't answer the question, so fair enough this is just an alternative approach)

list = [x for x in Tolkien_books if x in Lord_Of_The_Rings]
print(list)
combined_list = ["LOTR: [{}]".format(x) for x in Tolkien_books if x in Lord_Of_The_Rings] + [x for x in Tolkien_books if x not in Lord_Of_The_Rings]
print(combined_list)
  • The question is "Why is that?" – Mad Physicist Sep 10 '21 at 14:09
  • also they wants to change the strings in ```Tolkien_books```. Assigning someting to a variable named ```list``` is also not the best idea – phuycke Sep 10 '21 at 14:11
  • Might be a good idea to use Python 3 syntax in 2021, that is, write `print(x)` instead of `print x` :) – TDk Sep 10 '21 at 14:12
  • 1
    the OP didn't want to filter items – Tugay Sep 10 '21 at 14:12
  • Fair enough - I can see that Random_Pythoneer59 has answered the question. I've updated my answer to include a way of doing this using List Comprehension – Phillyp Henning Sep 10 '21 at 14:18
  • You can use an else inside the first list comprehension to avoid the need for the second. – ChrisOram Sep 10 '21 at 14:23
  • 1
    I was just reviewing your answer Chris. Looks clean :) I'll keep this in mind for the future. – Phillyp Henning Sep 10 '21 at 14:25
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 10 '21 at 18:05