[Tutor] Removing values from a dictionary if they are present in a list
Andre Engels
andreengels at gmail.com
Fri Apr 1 10:25:54 CEST 2011
On Fri, Apr 1, 2011 at 9:52 AM, ranjan das <ranjand2005 at gmail.com> wrote:
> I have the following information
>
> A={'g2': [4,5,3], 'g1': [1, 3]}
>
> B=[2,3,5]
>
> Now I want to remeove the elements in B if they are present (as values) in
> dictionary A.
>
> My expected solution is
>
> A= {'g2': [4], 'g1': [1] }
>
> I wrote the following piece of code which gives me thhe right code, but I am
> sure there must be a much shorter and more elegant way of doing it. Please
> suggest
>
> reject_list=[]
>
> for element in B:
>
> for key in A.keys():
>
> for i in range(len(A[key])):
>
> if element==A[key][i]:
>
> reject_list.append((key,A[key][i]))
>
>
>
> print reject_list
>
>
> for i in range(len(reject_list)):
>
> print (reject_list[i][0],reject_list[i][1])
>
> Index=A[reject_list[i][0]].index(reject_list[i][1])
>
> print (reject_list[i][0],reject_list[i][1],Index)
>
> del A[reject_list[i][0]][Index]
First, your loops are distinctly unpythonic. In many other languages
one does indeed go over a list or similar object by having a numeric
loop variable i, and then using list[i], but in Python we loop over
the list itself instead. Applying that to your code, and removing the
in-between prints, we get:
reject_list=[]
for element in B:
for key in A.keys():
for Aelement in A[key]:
if element == Aelement:
reject_list.append(key, Aelement)
for deleteelement in reject_list:
index = A[deletelement[0]].index(deleteelement[1])
del A[deleteelement[0]][index]
Next, realize that we are comparing each element in B with each
element in A, and then add information only on the element of A to the
list. Also, there is no need to add something twice if it occurs twice
in B. Thus, we can simplify this by just checking for each element of
A whether it is in B:
reject_list = []
for key in A.keys():
for element in A[key]:
if element in B:
reject_list.append(key, element)
for deleteelement in reject_list:
index = A[deletelement[0]].index(deleteelement[1])
del A[deleteelement[0]][index]
However, when working this way, we will have all elements from one key
in A together. We could also work with a separate list for each key,
and do those in turns:
for key in A.keys():
reject_list = []
for element in A[key]:
if element in B:
reject_list.append(element)
for element in reject_list:
index = A[key].index(element)
del A[key][index]
Still, we can go further. Why first create a list of things to do and
then do it? We can do it immediately; however, then we have to change
the loop variable, because things go wrong if you remove elements from
a list while looping over that same list.
for key in A.keys():
copy = A[key][:]
for element in copy:
if element in B:
index = A[key].index(element)
del A[key][index]
A further small shortening is done by realizing that the default way
of looping over a dictionary is to loop over its keys:
for key in A:
copy = A[key][:]
for element in copy:
if element in B:
index = A[key].index(element)
del A[key][index]
A following step is to see that we only use the keys to get to the
values. Why not use the values directly?
for value in A.values():
copy = value[:]
for element in copy:
if element in B:
index = value.index(element)
del value[index]
Can this still be shortened? Definitely. However, for the most obvious
shortening I have to make an assumption, namely that the values in A
are _not_ used elsewhere. Upto now we have removed elements from those
values; we now will replace the value instead. This means that in
Z = [0, 1]
A = {"Hello": Z, "Goodbye: [0,2]}
B = [0]
# The previous code
Z will have changed to [1]
whereas in
Z = [0, 1]
A = {"Hello": Z, "Goodbye: [0,2]}
B = [0]
# The upcoming code
Z will have remained [0,1]
With this proviso, we have:
for key in A:
newvalue = []
for element in A[key]:
if element not in B:
newvalue.append(element)
A[key] = newvalue
This on itself is not shorter than the previous forms, but it can be
used in a list expression like this:
for key in A:
A[key] = [element for element in A[key] if element not in B]
--
André Engels, andreengels at gmail.com
More information about the Tutor
mailing list