Delete dictionary keys that are out of bounds (python) - python

If you have a dictionary of integers:
d = {
1:[0],
2:[1],
3:[0,1,2,3,4],
4:[0],
5:[1],
6:[0,1,2,3,4],
11:[0],
22:[1],
33:[0,1,2,3,4],
44:[0],
55:[1],
66:[0,1,2,3,4]
}
You want to:
Validate that the keys are between 0 and 25.
Delete any keys that are outside of the range as they are not valid and will ruin the data set.
Dictionary keys are not naturally sorted.
Given, how would validate that your keys are in the required range?
My try:
for x,y in d.items():
if x<0 or x>25:
del d[x]
When ran I get the error:
RuntimeError: dictionary changed size during iteration
How would I compensate for this?

In your example, you are mutating the d while looping through it. This is bad.
The easiest way to do this if you don't need to change the original d is to use a dictionary comprehension:
d = {k: v for k, v in d.items() if 0 <= k <= 25}

If you want to delete keys while iterating, you need to iterate over a copy instead and pop keys that don't hold to your condition:
d = {1:[0], 2:[1], 3:[0,1,2,3,4], 4:[0], 5:[1], 6:[0,1,2,3,4], 11:[0], 22:[1], 33:[0,1,2,3,4], 44:[0], 55:[1], 66:[0,1,2,3,4]}
for k in d.copy(): # or list(d)
if not 0 <= k <= 25:
d.pop(k) # or del d[k]
Which Outputs:
{1: [0], 2: [1], 3: [0, 1, 2, 3, 4], 4: [0], 5: [1], 6: [0, 1, 2, 3, 4], 11: [0], 22: [1]}
As others have shown, reconstructing a new dictionary is always an easy way around this.
You can use a basic dict comprehension here:
{k: d[k] for k in d if 0 <= k <= 25}
Or even a functional approach with filter():
dict(filter(lambda x: 0 <= x[0] <= 25, d.items()))

You can use a dictionary comprehension:
d = { 1:[0], 2:[1], 3:[0,1,2,3,4], 4:[0], 5:[1], 6:[0,1,2,3,4], 11:[0], 22:[1], 33:[0,1,2,3,4], 44:[0], 55:[1], 66:[0,1,2,3,4] }
new_d = {a:b for a, b in d.items() if a <= 25 and a >= 0}
Output:
{1: [0], 2: [1], 3: [0, 1, 2, 3, 4], 4: [0], 5: [1], 6: [0, 1, 2, 3, 4], 11: [0], 22: [1]}

Related

Remove duplicate key, values from a dictionary such that each key or value appear only once

I have a python dictionary which contains multiple key,values which are actually image indexes. For e.g. the dictionary I have looks something as given below
{
1: [1, 2, 3],
2: [1, 2, 3],
3: [1, 2, 3],
4: [4, 5],
5: [4, 5],
6: [6]
}
this means that 1 is related to 1, 2 & 3. Similarly 2 is related to 1, 2 & 3. 6 has only 6 in it so it's related to none of the other elements. This is leading me to perform extra operations in my programs. I want the dictionary to be filtered and look like
# Preferred output
{
1: [2, 3],
4: [5],
6: []
}
So far I have tried
new_dict = dict()
# source is the original dictionary
for k,v in source.items():
ok = True
for k1,v1 in new_dict.items():
if k in v1: ok = False
if ok: new_dict[k] = v
This modifies the dictionary to
{1: [1, 2, 3], 4: [4, 5], 6: [6]}
I am looking for a more efficient and pythonic way to solve this problem.
This shows the preferred output:
source = {
1: [1, 2, 3],
2: [1, 2, 3],
3: [1, 2, 3],
4: [4, 5],
5: [4, 5],
6: [6]
}
new_dict = {}
seen = set()
for k, v in source.items():
if k in seen: continue
seen.add(k)
new_v = [i for i in v if i not in seen]
seen.update(new_v)
new_dict[k] = new_v
print(new_dict)
How about this, use my modification below to remove the first item in the list during each loop. I commented the line which does it.
new_dict = dict()
# source is the original dictionary
for k,v in source.items():
ok = True
for k1,v1 in new_dict.items():
if k in v1: ok = False
if ok: new_dict[k] = v[1:] #this line removes the first element.
My output is,
{1: [2, 3], 4: [5], 6: []}
your modified code:
ver 1:
new_dict = dict()
for k, v in source.items():
if not any(k in v1 for v1 in new_dict.values()):
new_dict[k] = v[1:]
ver 2:
tmp = dict()
for k, v in source.items():
tmp[tuple(v)] = tmp.get(tuple(v), []) + [k]
res = dict()
for k, v in tmp.items():
res[v[0]] = v[1:]
ver 3:
new_dict = {v[0]: list(v[1:]) for v in set(map(tuple, source.values()))}

how to store all the values of a list of lists and the frequence of their appearance as well as their index?

my code is this
idnt=[]
idntfrq=[]
for i in range(len(occ)):
idnt.append([])
idntfrq.append([])
for j in range(len(occ[i])):
for j2 in range(j,len(occ[i])):
for d in occ[i][j]:
idnt[i].append(d)
idntfrq[i].append([j])
occ[i][j].remove(d)
for d2 in occ[i][j2]:
if d==d2:
idntfrq[i][-1].append(j2)
occ[i][j2].remove(d)
I need the number of appearances of each value as well as their indexes
the list of lists is occ (50 lists inside with various lengths each)
the thought was to iterate over everything,store each value in the idnt[i] list and the
index of the list in which it appears to the idntfrq[i] list and then remove the
element from the list of the current itteration,the occ list should be empty after
that but it is not,i uploaded a prntscr of the occ[0][0] to see what i mean
NOTE: each list inside a list contains every element only once , but i want to count the
occurences across all the lists inside every occ[i] (for i in 50)and also keep the indexenter image description here
This code will do what you are asking:
mainList = [[1,2,3],[3,4,5],[1,5,9]]
d = {}
for l in mainList:
for item in l:
if item in d.keys():
d[item] +=1
else:
d[item] = 1
print(d)
Output:
{1: 2, 2: 1, 3: 2, 4: 1, 5: 2, 9: 1}
It gives the answer in a dictionary where keys are the items and the values is the number of appearances.
This output and be further formatted if needed.
If you need the indexes of each time a number appears you can simply add a dictionary di that has the items as keys and a list of index pairs at which the item appears as the values.
This can be done by adding di[item].append([idx,jdx]) and di[item] = [[idx,jdx]] inside the loop and defining it as di = {} before the loop like this:
mainList = [[1,2,3],[3,4,5],[1,5,9]]
d = {}
di = {}
idx = -1
for l in mainList:
idx += 1
jdx = -1
for item in l:
jdx += 1
if item in d.keys():
d[item] +=1
di[item].append([idx,jdx])
else:
d[item] = 1
di[item] = [[idx,jdx]]
print(d)
print(di)
Ouput:
{1: 2, 2: 1, 3: 2, 4: 1, 5: 2, 9: 1}
{1: [[0, 0], [2, 0]], 2: [[0, 1]], 3: [[0, 2], [1, 0]], 4: [[1, 1]], 5: [[1, 2], [2, 1]], 9: [[2, 2]]}
I think this works:
from collections import Counter
list_of_lists = [[1, 2, 3], [4, 1, 2], [3, 4, 5]]
counter = Counter()
for _list in list_of_lists:
counter.update(_list)

Dictionary of lists to nested dictionary

I have the following dictionary {44: [0, 1, 0, 3, 6]} and need to convert this to dict1 = {44: {0:0, 1:1, 2:0, 3:3, 4:6}} but my current for loop doesn't work:
maxnumbers = 5 #this is how many values are within the list
for i in list(range(maxnumbers)):
for k in list(dict1.keys()):
for g in dict1[k]:
newdict[i] = g
print(num4)
Can you help me? Thanks in advance.
You can use a dictionary comprehension with enumerate:
d = {44: [0, 1, 0, 3, 6]}
{k:dict(enumerate(v)) for k,v in d.items()}
# {44: {0: 0, 1: 1, 2: 0, 3: 3, 4: 6}}
Use a simple nested dictionary-comprehension that uses enumerate:
d = {44: [0, 1, 0, 3, 6]}
print({k: {i: x for i, x in enumerate(v)} for k, v in d.items()})
# {44: {0: 0, 1: 1, 2: 0, 3: 3, 4: 6}}
a = {44: [0, 1, 0, 3, 6]}
a= {i:{j:a[i][j] for i in a for j in range(len(a[i]))}}
print(a)
output
{44: {0: 0, 1: 1, 2: 0, 3: 3, 4: 6}}
Why your current implementation doesn't work:
for i in list(range(maxnumbers)):
for k in list(dict1.keys()):
for g in dict1[k]:
# this will iterate over all of the values in
# d1[k] and the i: v pair will be overwritten by
# the last value
newdict[i] = g
Taken in steps, this would look like:
# for value in [0, 1, 0, 3, 6]: Just take this set of values as an example
# first, value is 0, and say we are on i = 1, in the outer for loop
newdict[1] = 0
# Then it will progress to value = 1, but i has not changed
# which overwrites the previous value
newdict[1] = 1
# continues until that set of values is complete
In order to fix this, you'll want i and the values of dict1[k] to increment together. This can be accomplished with zip:
for index, value in zip(range(maxnumbers), dict1[k]):
newdict[index] = value
Also, if you need access to both the keys and values, use dict.items():
for k, values in dict1.items():
# then you can use zip on the values
for idx, value in zip(range(maxnumbers), values):
However, the enumerate function already facilitates this:
for k, values in dict1.items():
for idx, value in enumerate(values):
# rest of loop
This is more robust, since you don't have to find what maxnumbers is ahead of time.
To do this in the traditional for loop that you've been using:
new_dict = {}
for k, v in dict1.items():
sub_d = {} # create a new sub_dictionary
for i, x in enumerate(v):
sub_d[i] = x
# assign that new sub_d as an element in new_dict
# when the inner for loop completes
new_dict[k] = sub_d
Or, more compactly:
d = {44: [0, 1, 0, 3, 6]}
new_d = {}
for k, v in d.items():
new_d[k] = dict(enumerate(v))
Where the dict constructor will take an iterable of 2-element tuples as an argument, which enumerate provides

Python dictionary find key of max vlue

in python, if I want to find the max value of d, but the key only include 1,2,3 other than all the keys in the d. so how to do, thank you.
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
Just get the keys and values for the keys 1, 2 and 3 in a list of tuples, sort the list and get the first tuple element [0] key [0].
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
key_max_val = sorted([(k,v) for k,v in d.items() if k in [1,2,3]])[0][0]
print(key_max_val) # Outputs 1
You can use operator:
It will return you the key with maximum value:
In [873]: import operator
In [874]: d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
In [875]: max(d.iteritems(), key=operator.itemgetter(1))[0]
Out[875]: 1
I think this below should work (base on
#Mayank Porwal idea, sorry coz I can not reply):
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
max(v for k,v in d.items())
Use a generator and the max builtin function:
Max value
max(v for k,v in d.items() if k in [1,2,3])
Max key
max(k for k,v in d.items() if k in [1,2,3])

Nested list to dict with count groups

I have nested list:
L = [[15,10], [11], [9,7,8]]
and need count groups like [15, 10] is 0 group, [11] is 1 group and [9,7,8] is 2 group - output is dictionary:
print (d)
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
I try:
d = {k:v for k,v in enumerate(L)}
d = {k: oldk for oldk, oldv in d.items() for k in oldv}
print (d)
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
I think my solution is a bit over-complicated. Is there some better, more pythonic solution?
What about using:
d = {v: i for i,l in enumerate(L) for v in l}
which generates:
>>> {v: i for i,l in enumerate(L) for v in l}
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
The idea is as follows: first we iterate over L with enumerate(L) and we thus obtain the index i of the sublist vs. Next we iterate over every element v in vs. For every v we associate v with i in the dictionary.
If there are collisions - a value that occurs twice in L - then the last index will be used.
You can use:
d = {v: i for i in range(len(L)) for v in L[i]}
output:
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
iterating over L using range(len(L)) to access each list and assign each value as the key of the dictionary, and the index of the list as the value.

Categories

Resources