Delete a specific value from multi-value dictionary in python - 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)}

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

Quicker way to filter lists based on a check to external variable?

I have a variable = 'P13804'
I also have a list like this:
['1T9G\tA\t2.9\tP11310\t241279.81', '1T9G\tS\t2.9\tP38117\t241279.81', '1T9G\tD\t2.9\tP11310\t241279.81', '1T9G\tB\t2.9\tP11310\t241279.81', '1T9G\tR\t2.9\tP13804\t241279.81', '1T9G\tC\t2.9\tP11310\t241279.81']
You can see, if you split each item in this list up by tab, that the third item in each sub-list of this list is sometimes 'P11310' and sometimes is 'P13804'.
I want to remove the items from the list, where the third item does not match my variable of interest (i.e. in this case P13804).
I know a way to do this is:
var = 'P13804'
new_list = []
for each_item in list1:
split_each_item = each_item.split('\t')
if split_each_item[3] != var:
new_list.append(each_item)
print(new_list)
In reality, the lists are really long, and i have a lot of variables to check. So I'm wondering does someone have a faster way of doing this?
It is generally more efficient in Python to build a list with a comprehension than repeatedly appending to it. So I would use:
var = 'P13804'
new_list = [i for i in list1 if i.split('\t')[2] == var]
According to timeit, it saves more or less 20% of the elapsed time.

How to form a list from queried data?

I have the following code:
s = (f'{item["Num"]}')
my_list = []
my_list.append(s)
print(my_list)
As you can see i want this to form a list that i will then be able to store under my_list, the output from my code looks like this (this is a sample from around 2000 different values)
['01849']
['01852']
['01866']
['01883']
etc...
This is not what i had in mind, i want it to look like this
[`01849', '01852', '01866', '01883']
Has anyone got any suggestions on what i do wrong when i create the list? Thanks
You can fix your problem and represent this compactly with a list comprehension. Assuming your collection is called items, it can be represented as such, without the loop:
my_list = [f'{item["Num"]}' for item in items]
You should first initialize a list here, and then use a for-loop to populate it. So:
my_list = []
for values in range(0, #length of your list):
s = (f'{item["Num"]}')
my_list.append(s)
print(my_list)
Even better, you can also use a list comprehension for this:
my_list = [(f'{item["Num"]}') for values in range(0, #length of your list)]

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.

Change element of dictionary with values as list of lists

I have a dictionary similar to this
x ={'1': [['a','b'],['ac','d']], '2' : [['p','qa'],['r','s']]}
And I would like to access the individual strings i.e. a,b etc , compare if it has "a" in it, delete those.
The main question is - how do I access the strings? How do I change it?
I tried using nested loops, but was unable to change, as I guess assignment stmts do not work that way.
Any idea how to proceed with such situation?
Edit : The naive approach I used -
for item in x:
for ele in x[item]:
for i in ele:
i = #assign new value here using regex comparison
But when I try to print x after this, it stays same.
Obviously. assignment statements do not work this way. Any idea about how should I access the elements to change it?
>>> x ={'1': [['a','b'],['ac','d']], '2' : [['p','qa'],['r','s']]}
>>> for key in x:
... for n, item in enumerate(x[key]):
... x[key][n] = list(filter(lambda l: 'a' not in l, x[key][n]))
...
>>> x
{'2': [['p'], ['r', 's']], '1': [['b'], ['d']]}
In your example,
for item in x:
for ele in x[item]:
for i in ele:
i = #assign new value here using regex comparison
i is a copy of the string in ele, so assigning to it has no effect on the original. You need to modify the list ele. Possibly, ele[ele.index(i)] = #whatever. Note, however, that this will not work correctly if you have identical values in the list. It will only change the first one.
Not sure what you're actually trying to do, but it may be easier to use a list comprehension, at least for the innermost list. This will allow you to change each element of the innermost list. Perhaps,
for item in x.values():
for ele in item:
ele[:] = [#whatever for i in ele]
where ele[:] is needed to change the original inner list (just ele won't work), and I used the more Pythonic x.values() when we actually wanted the values, not the keys.

Categories

Resources