Nested list to dict with count groups - python

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.

Related

How can I create a whole new dictionary in last random dictionary QAQ

dic = {1: 1, 3: 3, 5: 6, 6: 6}
new_mappping is reverse from dic {1: [1], 3: [3], 6: [5, 6]}
for keys, values in new_mapping.items():
if keys not in new_sort.items():
if values not in new_sort.items():
new_sort = new_mapping
for keys,values in new_sort.items():
lens = len(values)
ky = {keys: values}
lll[lens] = ky
output from code:
{1: {3: [3]}, 2: {6: [5, 6]}}
desired output:
{1: {1: [1], 3: [3]}, 2: {6: [5, 6]}}
Code:
#INPUT
dic = {1: 1, 3: 3, 5: 6, 6: 6}
#Step 1 - change keys to values and values to keys
rev_dic={}
[rev_dic.update({v: rev_dic[v]+[k]}) if v in rev_dic else rev_dic.update({v: [k]}) for k, v in dic.items()]
#Step 2 - create new dictionary by list length
new_dic = {k:{} for k in range(1,max([len(v) for v in rev_dic.values()])+1)}
#Lastly, insert the dictionary in new_dic by dics' value list length
[new_dic[len(val)].update({key:val}) for key,val in rev_dic.items()]
new_dic
Output:
{1: {1: [1], 3: [3]}, 2: {6: [5, 6]}}

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

Delete dictionary keys that are out of bounds (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]}

Performance of inverse dictionary mapping

What would be the most efficient way to get all dict items with value == 3 and create a new dict?
Here is what I have thus far:
d = {1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1, ...}
new_d = {}
for item in d:
if d[item] == 3:
new_d[item] = d[item]
Is there a more efficient, simpler way to do this? Perhaps using a map?
You could use a dict comprehension:
new_d = {k:v for k, v in d.items() if v == 3}
Note that you should call d.iteritems() in Python 2.x to avoid creating an unnecessary list.
As you can see from the timeit.timeit tests below, this solution is more efficient:
>>> from timeit import timeit
>>> d = {1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}
>>>
>>> timeit('''
... new_d = {}
... for item in d:
... if d[item] == 1:
... new_d[item] = d[item]
... ''', 'from __main__ import d')
5.002458692375711
>>>
>>> timeit('new_d = {k:v for k, v in d.items() if v == 1}', 'from __main__ import d')
4.844044424640543
>>>
It is also a lot simpler, which is always good.

Categories

Resources