Python Theory About Equal Operator and Array Definition - python

I stumbled upon a theoretical question about how python works, and it got me puzzled. I tried to understand exactly what happened but couldn't find the answer in google - I'm a beginner, so I don't even know the terminology to make the apropriate search.
On the following code, when calling the function it changes myList, while I only wanted to create a list2 which was a copy of list1 (myList).
myList = [1,2,3,4,5,(1,2),(3,4)]
def onlyTuples(list1):
list2 = list1 # here is my question
for index,e in enumerate(list2):
if type(list2[index]) is not tuple:
list2[index] = (list2[index],)
return(list2)
print(myList)
create_new_list = onlyTuples(myList) # triggered by this call
print(myList)
It's all good if I change list2 = list1 to list2 = list(list1) and myList won't be changed when calling the function, but why?
The same thing doesn't happen with something like this:
a = 6
b = a
b = 7
print(a)
Any light upon the question will be appreciated. Thanks!

In python lists are passed by reference, so when you pass list to a function you pass its address in the memory. list2 = list1 won't create a copy of the list, it will save in list2 the address saved in list1. so change of list2 will change list1, but the function in the class list doesn't save the address, it copy a sequence to a list

To make a copy of a list, use:
newList = myList.copy()

Related

Python list - call function with different values

def check(val, list=[]):
list.append(val)
return list
list1=check("a")
list2=check("b",[])
list3=check("c")
If I run list1 and check the output it shows ["a"]
But, If I run list1, list2 and list3 in one
cell and check for list1 it shows ['a','c'], can someone please explain why is it so?
This is the right way to do this:
def check(val, values=None):
if values is None:
values = []
values.append(val)
return values
list1 = check("a")
list2 = check("b", [])
list3 = check("c")
Default argument values should not be mutable. You can find a good explanation here,
And list is a poor name for a variable, because list is a built-in type, as are str, set, dict.
It seems that list1 and list3 share same object.
You can try this:
def check(val, list=[]):
list.append(val)
print(hex(id(list)))
return list
list1=check("a")
list2=check("b")
list3=check("c")
print(list1)
print(list2)
print(list3)

Why doesn't python print everything I wrote into it?

I was doing some exercises in python python and I bumped into a problem. I already printed a list reversed and I wanted to print the reversed elements in separate lines too but for some reason it only prints the first one and if I put the first print into comment it prints out the loop just fine. Why?
def main():
pass
if __name__ == '__main__':
main()
list1 = [10, 20, 30, 40, 50]
def reverse_list(l1):
l2 = []
for i in range(len(l1)):
l2.append(l1.pop())
return l2
print(reverse_list(list1))
pass
def reverse_print(l):
listr = reversed(l)
for j in listr:
print(j)
reverse_print(list1)
print("Complete...")
In python, data types are divided into mutable and immutable types:
Mutable object: the value in the memory pointed to by the object can be changed
Immutable object: The value in the memory pointed to by the object cannot be changed, so when the value pointed to by the variable changes, it is equivalent to copying the original value and storing it in a new address, and the variable points to this new address.
a = [1,2,3,4]
a_ref = a
print(a) # [1,2,3,4]
a_ref[0] = 5
print(a) # [5,2,3,4]
It can be seen from the above code
a, a_ref are exactly the same
a and a_ref have the same memory location
modification to a_ref, a will also be changed
for example:
a = [1,2,3,4]
def somefunc(a2):
a2.append(5)
print(a) # [1,2,3,4]
somefunc(a)
print(a) # [1,2,3,4,5]
Normally, it won't change a by calling somefunc(a)
BUT
Since a2 is a reference to a and points to the same memory location, when a2 is modified, it will also be modified to a
in your code:
when you calling reverse_list(list1), l1 is a reference to list1, when you pop the element from l1, it will also pop the element in list1
so after called reverse_list(list1), list1 is empty, that why reverse_print(list1) do not print anything
Sollution
def reverse_list(l1):
l1_copy = l1[:] # copy the whole list
l2 = []
for i in range(len(l1_copy)):
l2.append(l1_copy.pop())
return l2
when you call l1_copy = l1[:]
than l1_copy won't point to same memory location
so l1 and list1 won't modified when modifica l1_copy
PS: english is my second langage, so there maybe have some gramma mistake, please excuse me
at the second print list1 has been emptied out from using the pop() method in reverse_list.
to reverse a list perhaps you should use the reverse()method like the following example:
List1 = [1,2,3]
List1.reverse()
print(List1) # [3,2,1]

Relationship between elements of two list: how to exploit it in Python?

SO here is my minimal working example:
# I have a list
list1 = [1,2,3,4]
#I do some operation on the elements of the list
list2 = [2**j for j in list1]
# Then I want to have these items all shuffled around, so for instance
list2 = np.random.permutation(list2)
#Now here is my problem: I want to understand which element of the new list2 came from which element of list1. I am looking for something like this:
list1.index(something)
# Basically given an element of list2, I want to understand from where it came from, in list1. I really cant think of a simple way of doing this, but there must be an easy way!
Can you please suggest me an easy solution? This is a minimal working example,however the main point is that I have a list, I do some operation on the elements and assign these to a new list. And then the items get all shuffled around and I need to understand where they came from.
enumerate, like everyone said is the best option but there is an alternative if you know the mapping relation. You can write a function that does the opposite of the mapping relation. (eg. decodes if the original function encodes.)
Then you use decoded_list = map(decode_function,encoded_list) to get a new list. Then by cross comparing this list with the original list, you can achieve your goal.
Enumerate is better if you are certain that the same list was modified using the encode_function from within the code to get the encoded list.
However, if you are importing this new list from elsewhere, eg. from a table on a website, my approach is the way to go.
You could use a permutation list/index :
# I have a list
list1 = [1,2,3,4]
#I do some operation on the elements of the list
list2 = [2**j for j in list1]
# Then I want to have these items all shuffled around, so for instance
index_list = range(len(list2))
index_list = np.random.permutation(index_list)
list3 = [list2[i] for i in index_list]
then,with input_element:
answer = index_list[list3.index(input_element)]
Based on your code:
# I have a list
list1 = [1,2,3,4]
#I do some operation on the elements of the list
list2 = [2**j for j in list1]
# made a recode of index and value
index_list2 = list(enumerate(list2))
# Then I want to have these items all shuffled around, so for instance
index_list3 = np.random.permutation(index_list2)
idx, list3 = zip(*index_list3)
#get the index of element_input in list3, then get the value of the index in idx, that should be the answer you want.
answer = idx[list3.index(element_input)]
def index3_to_1(index):
y = list3[index]
x = np.log(y)/np.log(2) # inverse y=f(x) for your operation
return list1.index(x)
This supposes that the operations you are doing on list2 are reversible. Also, it supposes that each element in list1 is unique.

Upon shuffling I get a None object. What is wrong?

I have shuffled the list and assigned it to another variable and when I am trying to print it, it is giving output as None? What is wrong ?
list1 = [1,2,3,4,5,6]
list2 = shuffle(list1)
print list2
The random.shuffle() function is designed to take a list and shuffle its contents. It does not return the shuffled list. The documentation states:
Shuffle the sequence x in place.
As such, if you try to assign the return to a variable you will get None.
You can do the following instead:
list1 = [1,2,3,4,5,6]
shuffle(list1)
print list1
If you wish to preserve your original list order:
list1 = [1,2,3,4,5,6]
list2 = list1[::] # make a copy
shuffle(list2)
print list2
Shuffle() function is not accessible directly, so we need to import shuffle module and then we need to call this function using random static object.
#!/usr/bin/python
import random`
list = [1, 2, 3, 4, 5];
random.shuffle(list)
print "list : ", list

Delete a specific value from multi-value dictionary in python

``I have a dictionary in python like this.
dictionary = {"00":[1,2,3,4,5,6,7,8,9],"01":[1,2,3,4,5,6,7,8,9],"02":[1,2,3,4,5,6,7,8,9],"03":[1,2,3,4,5,6,7,8,9],"04":[1,2,3,4,5,6,7,8,9]........up-to "99":[1,2,3,4,5,6,7,8,9]}
I have to delete the value 2 from the list of "00".I tried it using following statement.
del (dictionary[key][dictionary[key].index(sudokumatrix[i][iindex])]).
Here key has value "00" and sudokumatrix[i][iindex] has value 2.But i got resulting dictionary as
{"00":[1,3,4,5,6,7,8,9],"01":[1,3,4,5,6,7,8,9],"02":[1,3,4,5,6,7,8,9],"03":[1,3,4,5,6,7,8,9],"04":[1,3,4,5,6,7,8,9].....}.
I have to get the result as:
{"00":[1,3,4,5,6,7,8,9],"01":[1,2,3,4,5,6,7,8,9],"02":[1,2,3,4,5,6,7,8,9],"03":[1,2,3,4,5,6,7,8,9],"04":[1,2,3,4,5,6,7,8,9]....}
I am posting the whole code here:
dictionary = dict()
zerotonine = "123456789"
list2 = list(zerotonine)
list2 = [int(i) for i in list2]
sudokumatrix=[]
for p in range(9):
for q in range(9):
keyis=str(p)+str(q)
dictionary[keyis] = list2
for i in range(9):
initialinput = [1,2,3,4,5,6,7,8,9]
list1=list(initialinput)
list1 = [int(i) for i in list1]
sudokumatrix.append(list1)
key = "00"
del dictionary[key][dictionary[key].index(sudokumatrix[0][1])]
print dictionary
EDIT == I guess(since the generation of dictionary is not given) ==EDIT.
The reason is that the values of keys '00', '01', ... are pointing to the same list. Modifying one of them will definitely affect the others.
Try using this to generate your dict
dictionary = dict((str(x).zfill(2), range(1, 10)) for x in range(100))
Your code of this part is actually not wrong, but to use list.remove() will make it much better.
The issue has to do with pointers.
replace this:
dictionary[keyis] = list2
with this:
dictionary[keyis] = [int(i) for i in list2]
You're creating list2 correctly, but when you go into the loop Python doesn't make a brand new copy of it with every iteration. It makes a pointer to the original list. Python sees:
dictionary[keyis] = list2
and says "oh, list2? I recognize that name! I have that as an object in memory already! I'll save some space by just updating the original copy and linking it here! Any time someone wants to view it or update it I'll just deal with the original and everything will be awesome forever!!!"
OK, so maybe the python interpreter isn't that enthusiastic, but that's how I like to think of it. The end result is that all of your dictionary values are pointing at the original list.
If you don't mind deleting every occurrence of 2 in the list, you can use list comprehension:
dictionary["00"] = [i for i in dictionary["00"] if i != 2]
This will create a new list, and will avoid altering the other values, as it appears all your dictionary values reference the same list.
EDIT: Yep your dictionary values reference the same list
you could use dictionary and list comprehension to create your dictionary
dictionary = {str(x):[i for i in range(10)] for x in range(100)}

Categories

Resources