Python Forum
manipulating two lists - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: manipulating two lists (/thread-25922.html)



manipulating two lists - rancans - Apr-15-2020

Hi,

I do not understand why am i getting all the double usernames executing the code below:

existing_accounts = ["Marcis", "John", "Tim"]
new_accounts = ["Sarah", "Marcis", "Tim", "Marcis"]

for existing_account in existing_accounts:
	for new_account in new_accounts:
		if new_account == existing_account:
			print(new_account + " is already taken!")
			new_accounts.remove(new_account)
		else:
			print (new_account + " you are now registered.")
			existing_accounts.append(new_account)
			
print(existing_accounts)
print(new_accounts)
As the result i want only unique usernames in existing_account list.

Thanks.


RE: manipulating two lists - bowlofred - Apr-15-2020

You don't need the outer loop at all (for existing acount....). Just loop over the new accounts and check if they are in existing accounts.

    if new_account in existing_accounts:
        # report they already exist
    else:
        # create new account.



RE: manipulating two lists - rancans - Apr-15-2020

(Apr-15-2020, 08:42 PM)bowlofred Wrote: You don't need the outer loop at all (for existing acount....). Just loop over the new accounts and check if they are in existing accounts.

    if new_account in existing_accounts:
        # report they already exist
    else:
        # create new account.
Now I get this working but there are left two Marcis entries in the new users list after execution. How to tackle this?

existing_accounts = ["Marcis", "John", "Tim"]
new_accounts = ["Sarah", "Marcis", "Tim", "Marcis"]
for new_account in  new_accounts:
    if new_account in existing_accounts:
    	print(new_account + " is already taken!")
    	new_accounts.remove(new_account)
    else:
    	print (new_account + " you are now registered.")
    	existing_accounts.append(new_account)
    	new_accounts.remove(new_account)
			
print(existing_accounts)
print(new_accounts)



RE: manipulating two lists - stullis - Apr-15-2020

The quick way is to change new_accounts into a set instead of a list; sets store unique values only.

existing_accounts = ["Marcis", "John", "Tim"]
new_accounts = ["Sarah", "Marcis", "Tim", "Marcis"]

for new_account in  set(new_accounts):
    if new_account in existing_accounts:
        print(new_account + " is already taken!")
        new_accounts.remove(new_account)
    else:
        print (new_account + " you are now registered.")
        existing_accounts.append(new_account)
        new_accounts.remove(new_account)
             
print(existing_accounts)
print(new_accounts)
Something to be aware of when iterating over lists: alterations to the list inside the loop can cause problems. For instance, if Tim did not have an existing account, he would likely not be listed in new_accounts at the end. This is due to the indices of the contents changing because of the removal of Marcis, but the index for the loop doesn't adjust accordingly. Remove Tim from existing_accounts and run it again; you should find a problem.


RE: manipulating two lists - bowlofred - Apr-15-2020

Why would you care about the contents of that list? I would probably just ignore it and not look at it after the loop.

But the technical reason is that trying to remove elements from a list while iterating through that list is not allowed.

Don't do this:
for i in mylist:
    mylist.remove(i)
It confuses the iterator and you won't necessarily loop over everything properly.

You could make a copy of the list and then iterate over the copy.
for i in list(mylist):  # iterates over a copy
    mylist.remove(i)



RE: manipulating two lists - deanhystad - Apr-15-2020

Removing items from the list you are iterating is bad. You can kind of do it if you start from the end and work backward, but it is far better to build a new list.
existing_accounts = ["Marcis", "John", "Tim"]
new_accounts = ["Sarah", "Marcis", "Tim", "Marcis"]

invalid_accounts = []
for account in new_accounts:
    if account in existing_accounts:
        invalid_accounts.append(account)
    else:
        existing_accounts.append(account)
             
print(existing_accounts)
print(invalid_accounts)

# If you want to put invalid accounts back in "new_accounts"
new_accounts[:] = invalid_accounts



RE: manipulating two lists - stullis - Apr-15-2020

The reason to care is simple: this is a toy project. In a real project, the new user would be signed up and the iterative problem would preclude that. Plus, the OP is learning and needs to learn about those problems, why they happen, and how to work around them.


RE: manipulating two lists - rancans - Apr-16-2020

(Apr-15-2020, 09:51 PM)stullis Wrote: The quick way is to change new_accounts into a set instead of a list; sets store unique values only.

existing_accounts = ["Marcis", "John", "Tim"]
new_accounts = ["Sarah", "Marcis", "Tim", "Marcis"]

for new_account in  set(new_accounts):
    if new_account in existing_accounts:
        print(new_account + " is already taken!")
        new_accounts.remove(new_account)
    else:
        print (new_account + " you are now registered.")
        existing_accounts.append(new_account)
        new_accounts.remove(new_account)
             
print(existing_accounts)
print(new_accounts)
Something to be aware of when iterating over lists: alterations to the list inside the loop can cause problems. For instance, if Tim did not have an existing account, he would likely not be listed in new_accounts at the end. This is due to the indices of the contents changing because of the removal of Marcis, but the index for the loop doesn't adjust accordingly. Remove Tim from existing_accounts and run it again; you should find a problem.

Thank you for your patience. Do I understand correctly, that when you changed the list to set where I had only one "Marcis" value to iterate through and remove from new_accounts. That is why I get the other "Marcis" value which is not removed from the new_accounts list?

I still do not understand how come I don't see "Marcis is already taken!" message in this code:
existing_accounts = ["John", "Tim", "Sarah", "Marcis"]
new_accounts = ["Sarah", "Marcis", "Tim"]
 
for new_account in  new_accounts:
    if new_account in existing_accounts:
        print(new_account + " is already taken!")
        new_accounts.remove(new_account)
    else:
        print (new_account + " you are now registered.")
        existing_accounts.append(new_account)
        new_accounts.remove(new_account)
and why am I seeing "Marcis" in the new_accounts list, when it should be removed when iterating through the loop.


RE: manipulating two lists - deanhystad - Apr-16-2020

To see the problem, try running this code:
existing_accounts = ["John", "Tim", "Sarah", "Marcis"]
new_accounts = ["Sarah", "Marcis", "Tim"]
  
i = 0
while i < len(new_accounts):
    new_account = new_accounts[i]
    if new_account in existing_accounts:
        print(new_account + " is already taken!")
        new_accounts.remove(new_account)
    else:
        print (new_account + " you are now registered.")
        existing_accounts.append(new_account)
        new_accounts.remove(new_account)
    i += 1
    print(i, new_accounts)
Output:
Sarah is already taken! 1 ['Marcis', 'Tim'] Tim is already taken! 2 ['Marcis']
Removing Sarah from new_accounts makes Marcis the first element in the list. The second time through the loop looks at new_accounts[1], and that is Tim. We skipped Marcis because we change the list we are using to iterate.

One of many ways to get around this problem is create a copy of the list to use for the iterator.
existing_accounts = ["John", "Tim", "Sarah", "Marcis"]
new_accounts = ["Sarah", "Marcis", "Tim"]
  
for new_account in new_accounts[:]:  # This iterates over a copy of new_accounts
    if new_account in existing_accounts:
        print(new_account + " is already taken!")
    else:
        print (new_account + " you are now registered.")
        existing_accounts.append(new_account)
    new_accounts.remove(new_account)