List non-mutating method - python

Is there in python any method that instead of mutate the original list it returns a new object?
In JavaScript there is at least one:
const originalArray = [1,2,3]
originalArray.concat(4) // returns a new array

In Python, this will return a new list:
originalArray = [1,2,3]
originalArray + [4]
Or if you want to create a new copy of the list use slices:
originalArray[:]
List comprehensions will also create a new list:
[x for x in originalArray]
This is yet another way:
import copy
copy.copy(originalArray)
And there's also the built-in copy() method, as shown in Ronald's answer.

You can simply use the copy method:
list1 = ['a','b','c']
list2 = list1.copy()
list1 is list2, list1 == list2
returns
(False, True)
Showing that you have new object with the same content.

Related

Python Theory About Equal Operator and Array Definition

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()

How to add 0's into two dimensional list using list comprehension in python?

I'm trying to convert this for loop into "list comprehension" format if possible:
This loop adds 0 into two dimensional list
test_list = [['string1'],['string2'],['string3']]
for i in range(len(test_list)):
test_list[i].insert(1, 0)
output:
test_list = [['string1',0],['string2',0],['string3',0]]
I've tried this but for some reason it doesn't work.
test_list = [test_list[i].insert(1, 0) for i in range(len(test_list))]
It doesn't work, because list.insert() modifies the list in-place and returns None, so you will end up with a list of Nones which are return values from all .insert()s.
List comprehension format is not adequate for what you want, because it is designed to create new lists, and you seem to want to modify the list in-place. If you want to create new lists instead, you can use this:
test_list = [sublist + [0] for sublist in test_list]
this works because the + operator on lists creates and returns a new list.
Is your question "what's the reason?"
The line
test_list = [test_list[i].insert(1, 0) for i in range(len(test_list))]
means "make a list of the return values of this expression".
The return value of the expression [].insert() is None. test_list will be set to a list of Nones.

The append() method issue of list in Python3

for example,i got a list:
mylist = [1,2,3]
we all know append() can add a new item at the end of the list like that:
mylist.append(4)
now the mylist is [1,2,3,4]
my issue is what happened when mylist append itself????
mylist.append(mylist)
at first i think it will look like this:
[1,2,3,4,[1,2,3,4]]
but when i print it, output is [1,2,3,4,[...]],so i print the mylist[5] and it's same to the mylist:[1,2,3,4,[...]]
so you can loop the last item of list endless,and the last item always be the same to original mylist!!!!!
anyone can tell me why is that????????
Because you aren't appending a copy of the list, but the actual list object itself. Consider this program:
mylist = [1,2,3,4]
mylist.append(mylist)
assert id(mylist) == id(mylist[4])
The final item of the list is a reference to the list itself, so you have a fully recursive, self-referential data structure.
If you want the result [1,2,3,4,[1,2,3,4]], then you need to append a copy of the original list, like so:
mylist = [1,2,3,4]
mylist.append(list(mylist))
assert mylist == [1,2,3,4,[1,2,3,4]]
It's doing that because you're telling Python to append a list(my_list) to a list. If you want to extend the list with the contents of the list, you can do this:
new_list = old_list + new_list
output: [1, 2, 3, 4, 1, 2, 3, 4]
or you can use the extend method.
old_list.extend(my_list)
Which will modify the old_list in place.

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