Variable changing itself? - python

So I am working on a project, and this bit of code is acting funny. I wanted a function that would take a list (list1) , make a copy (list2) of that list and trim certain objects from the copy only. I only wrote code to subtract items from the copy, be the original keeps getting changed as well.(?) I just don't understand how the original list (list1) is being subtracted from. Code underneath, thank you in advance for your help..
def copyandtrim(w, x, y, z):
list1 = [w, x, y ,z]
list2 = []
list2 = (list1)
testlen = (len(list2))
for y in range(testlen - 1):
if (list2[y])[2] == 0:
list2.remove(list2[y])
else:
pass

In order to make a copy of list1 in list2 you should do this:
list2 = list1[:]
But be careful, using list2.remove(list2[y]) changes list2, so further indexes are shifted as well. I would suggest this alternative to your loop:
list2 = [x for x in list1 if x[2] != 0]

list2 = list1 doesn't actually do a deep copy of the list object. It simply points list2 to refer to the same list object. To get a copy, the easiest way is to use:
list2 = list1[:]

To copy list in python you should use slice operation:
list2 = list1[:]

Related

Append a list that’s in another list

I’m trying to append a list that’s in another list.
import random
list1 = []
list2 = []
list3 = [list1, list2]
Index = random.choice(list3)
Index = list3.index(Index)
print(Index)
list3[Index].append(“Test”)
print(list3[Index])
I want it to add “test” to either list1 or list2 depending on the value of index.
For some reason, if I repeat the process twice, and the value of index changes, “Test” is added twice to the same list. How do I accomplish this?
random.choice returns one of the items in the given list, which in this case are the references to, rather than the indices of, list1 and list2.
You should append directly to the list returned by random.choice instead:
import random
list1 = []
list2 = []
list3 = [list1, list2]
lst= random.choice(list3)
lst.append('Test')
print(list3)
This can output:
[['Test'], []]

Iterating over 2 lists at once and comparing the elements

This is just a small part of my homework assignment. What im trying to do is iterate through list1 and iterate backwards through list2 and determine if list2 is a reversed version of list1. Both lists are equal length.
example: list1 = [1,2,3,4] and list2 = [4,3,2,1]. list2 is a reversed version of list1. You could also have list1 = [1,2,1] and list2 = [1,2,1] then they would be the same list and also reversed lists.
Im not asking for exact code, im just not sure how i would code this. Would i run 2 loops? Any tips are appreciated. Just looking for a basic structure/algorithm.
edit: we are not allowed to use any auxiliary lists etc.
You can just iterate backwards on the second list, and keep a counter of items from the start of the first list. If items match, break out of the loop, otherwise keep going.
Here's what it can look like:
def is_reversed(l1, l2):
first = 0
for i in range(len(l2)-1, -1, -1):
if l2[i] != l1[first]:
return False
first += 1
return True
Which Outputs:
>>> is_reversed([1,2,3,4], [4,3,2,1])
True
>>> is_reversed([1,2,3,4], [4,3,2,2])
False
Although it would be easier to just use builtin functions to do this shown in the comments.
The idea here is that whenever you have an element list1[i], you want to compare it to the element list2[-i-1]. As required, the following code creates no auxiliary list in the process.
list1 = [1, 2, 3]
list2 = [3, 2, 1]
are_reversed = True
for i in range(len(list1)):
if list1[i] != list2[-i - 1]:
are_reversed = False
break
I want to point out that the built-in range does not create a new list in Python3, but a range object instead. Although, if you really want to stay away from those as well you can modify the code to use a while-loop.
You can also make this more compact by taking advantage of the built-in function all. The following line instantiate an iterator, so this solution does not create an auxiliary list either.
are_reversed = all(list1[i] == list2[-i - 1] for i in range(len(list2))) # True
If you want to get the N'th value of each list you can do a for loop with
if (len(list1) <= len(list2):
for x in range(0, len(list1):
if (list1[x] == list2[x]):
#Do something
else:
for x in range(0, len(list2):
if (list1[x] == list2[x]):
#Do something
If you want to check if each value of a list with every value of another list you can nestle a for loop
for i in list1:
for j in list2:
if (list1[i] == list2[j]):
//Do something
EDIT: Changed code to Python

How to delete a dictionary from a list based on values from another dictionary in a list?

I've spent about 6 hours on this, so I feel justified in asking a question. :)
My problem
list1 = [
{extension: 1000, id: 1}
{extension: 1001, id: 1}
{extension: 1000, id: 2}
]
list2 = [
{Stationextension: 1000, id: 1, name: bob}
{Stationextension: 1001, id: 1, name: sal}
{Stationextension: 1000, id: 2, name: cindy}
]
My pseudo code is this.
Delete list2[d] (whole dictionary from list of dicts) where list1[d]['extension'] == list2[d]['Stationextension'] AND id == id.
List 1 is much smaller and has to stay unchanged relative to list 2 if that matters.
Using Python3.3, I have something like
[x for x in list2 if (list1[x]['stationExtension'] == x.get('extension'))]
Thanks !
list2 = [x for x in list2 if {'extension': x['Stationextension'], 'id': x['id']} not in list1]
or, if you know that the lengths and indexes will match:
list2 = [y for x,y in itertools.izip(list1, list2) if x['extension'] == y['StationExtension'] and x['id'] == y['id']]
The right way to do this is to use the right data structures for the job. Instead of figuring out how to search a list based on a key, use a dict with that key. For example:
dict1 = {x['extension']: x for x in list1}
Now, you can just write this:
[x for x in list2 if x['stationExtension'] in dict1}
Elsewhere in your question, it seems like you wanted to use the extension and the id, not just the extension, as a key. But that's just as easy; you can use a tuple:
dict1 = {(x['extension'], x['id']): x for x in list1}
[x for x in list2 if (x['stationExtension'], x['id']) in dict1}
If you want to know why your code doesn't work… let's look at it:
[x for x in list2 if (list1[x]['stationExtension'] == x.get('extension'))]
list1[x] is trying to use the dict as an index, which doesn't mean anything. What you really want to say is "if, for any element of list1, element['stationExtension'] == x.get('extension')". And you can translate that almost directly to Python:
[x for x in list2
if any(element['stationExtension'] == x.get('extension')
for element in list1)]
And of course to add the and element['id'] == x['id'] onto the end of the condition.
But again, the dict is a better solution. Besides being a whole lot simpler to read and write, it's also more efficient. Searching for any matches in a list requires checking each element in the list; searching for any matches in a dict just requires hashing the key and looking it up in a hash table. So, this way takes O(NM) time (where N is the length of list1, and M is the length of list2), while the dict only takes O(M) time.
Assuming that you want to delete items from list2 with the same value in "Stationextention" on list2 and "extention" on list 1 -
You better first create a set with all values to delete - that will avoid a linear search at each time you want to check if an entry will stay:
indexes = set(item["extention"] for item in list1)
And - one thing that happens is that you usually can't iterate over a list and delete items from it while at it:
new_list2 = []
for item in list2:
if item["Stationextention"] not in indexes:
new_list2.append(item)
list2 = new_list2
Python 2.7:
removelist=[]
for i,x in enumerate(list2):
if x['Stationextension'] == list1[i]['extension'] and x['id'] == list1[i]['id']:
removelist+=[i]
And once you've decided what to delete:
for x in removelist:
del list1[x]

Altering tuples within a list - is this the best way?

I have a list of tuples this form:
my_list = [(a,b),(c,d),(e,f)]
I want to do something to the second member of each tuple. It's fine if I need to make a new list, though I won't need the old one.
This is what I am doing now:
new_list = []
for x,y in my_list:
new.list.append((x,my_function(y)))
This works but feels clunky, is it the best/most pythonic/fastest way?
Use a list comprehension to generate new tuples:
new_list = [(x, my_function(y)) for x, y in my_list]
This comes down to the same as your version, but avoids the repeated .append() calls and builds the list in one go.
using a list comprehension is usually cleaner:
[(x, function(y)) for x,y in my_list]
you can then write it back onto my_list or give it a new variable name if you choose:
my_list = [(x, function(y)) for x,y in my_list]
Or even do a slice assignment to replace my_list in place:
my_list[:] = [(x, function(y)) for x,y in my_list]

Python append adds an item to every variable

I'm iterating on a list and attempting to create sublists from its items. Every time I append to a variable, the value is added to every other variable that I have defined. I've stripped down the code substantially to illustrate.
item = 'things.separated.by.periods'.split('.')
list1 = list2 = []
i = item.pop(0)
print i
list1.append(i)
i = item.pop(0)
print i
list2.append(i)
print(item, list1, list2)
Returns:
things
separated
(['by', 'periods'], ['things', 'separated'], ['things', 'separated'])
What I expected:
things
separated
(['by', 'periods'], ['things'], ['separated'])
I think this might by answered here, but I'm not sure how to apply this fix to my circumstances. Thanks in advance!
The problem is the line
list1 = list2 = []
This makes list1 and list2 refer to the exact same list, so that if you append an item to one you also append it to the other. Change it to
list1 = []
list2 = []
list1 = list2 = []
You are setting list1 to be the exact same list as list2. Therefore, they basically mean the same thing.
To fix this, try something like this:
list1, list2 = [], []

Categories