Sorting alphanumeric keys of a dictionary in python - python

I have a python dictionary whose keys have the following pattern
<some x number of digits/alphabets> <some y number of alphabets><some z number of digits>
I want to sort the dictionary based on this keys.
For e.g
01IB0610, 01IB062, 01IB064
should be 01IB062, 01IB064 01IB0610
Complete example is something like this:
{ '01IB0610' : {'a' : [] , 'b': [] }, '01IB062' : {'a' : [] , 'b': [] } , '01IB064' : {'a' : [] , 'b': [] }
Final Output should be:{ '01IB062' : {'a' : [] , 'b': [] }, '01IB064' : {'a' : [] , 'b': [] } , '01IB0610' : {'a' : [] , 'b': [] }

import re
def key_func(s):
return [int(x) if x.isdigit() else x for x in re.findall(r'\D+|\d+', s)]
sorted_keys = sorted(d, key=key_func)
Example:
>>> d = {'01IB0610': 'foo', '01IB062': 'bar', '01IB0604': 'baz'}
>>> sorted(d, key=key_func)
['01IB062', '01IB0604', '01IB0610']

I'm not sure I totally get the sorting criteria, but you can use an OrderedDict to have a dict that keeps particular order.
from collections import OrderedDict
import re
d = {'01IB0610': 1, '01IB062': 2, '01IB064': 3}
def criteria(x):
number = int(re.sub('[^0-9]', '', x[0]) )
length = len(x[0])
return length, number
d = OrderedDict( sorted( d.items(), key = criteria ) )
d.keys()
>> ['01IB062', '01IB064', '01IB0610']
This creates an OrderedDict where the order of the elements in the original dict is based on a hierarchical sort of the keys of those elements. The first criteria is the length of the key, ie 01IB0610 comes after 01IB064 because its longer. The second criteria is based on the digits in the key, ie 01062 is before 01064.

Related

simplify code using an inverse dictionary in python

Consider some mapping my_map that defines the order of some keys, and some dictionary my_dict that maps the same keys into some values:
my_map = {'x' : 2, 'y' : 0, 'z' : 1}
my_dict = {'x' : 'foo', 'z' : 'bar', 'y' : 'baz'}
I want to get an ordered list of the values of my_dict using the order defined by my_map. My best approach of getting there is:
inv_map = {v: k for k, v in my_map.items()}
ordered_list = [my_dict[k] for k in [inv_map[d] for d in range(len(my_map))]]
Is there a less clunky way of doing the same?
You could use the sorted function to order your map by value and then convert it:
[my_dict[k] for k in sorted(my_map, key=lambda key: my_map[key])]
Somewhat cleaner at least!
Let's make sure that it works:
>>> my_map = {'x' : 2, 'y' : 0, 'z' : 1}
>>> my_dict = {'x' : 'foo', 'z' : 'bar', 'y' : 'baz'}
>>> [my_dict[k] for k in sorted(my_map, key=lambda key: my_map[key])]
['baz', 'bar', 'foo']
You can actually use sorted very efficiently here using dict.get:
[my_dict[k] for k in sorted(my_map, key=my_map.get)]
In action:
>>> my_map = {'x' : 2, 'y' : 0, 'z' : 1}
>>> my_dict = {'x' : 'foo', 'z' : 'bar', 'y' : 'baz'}
>>> [my_dict[k] for k in sorted(my_map, key=my_map.get)]
['baz', 'bar', 'foo']
Depends on the situation you can init final list and pass items to the needed positions
result = [None] * len(my_dict)
for k, v in my_dict.items():
result[my_map[k]] = v
Still another variation (I think it's different from already presented solutions):
[x[1] for x in sorted(my_dict.items(), key=lambda elem: my_map[elem[0]])]
Testing code:
my_map = {'x' : 2, 'y' : 0, 'z' : 1}
my_dict = {'x' : 'foo', 'z' : 'bar', 'y' : 'baz'}
print(my_dict.items())
sorted_result=[x[1] for x in sorted(my_dict.items(), key=lambda elem: my_map[elem[0]])]
print(sorted_result)
Or a bit differently:
sorted_result=list(zip(*sorted(my_dict.items(), key=lambda elem: my_map[elem[0]])))[1]
I wanted to use zip() to split a list of tuples into 2 lists, but in Python 3 zip() returns iterator (not a list), so (as suggested in Transpose/Unzip Function (inverse of zip)?) I wrapped it in list()
you can use sorted with the values from my_dict and a key function that sorts them with the values from my_map
ordered_list = sorted(my_dict.values(), key=lambda s:my_map[{v: k for k, v in my_dict.items()}[s]])
if it's sorted the wrong way you can use reverse=True

Getting duplicates from nested dictionary

I'm fairly new to python and have the following problem. I have a nested dictionary in the form of
dict = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
and would like to find all the keys that have the same values. The output should look similar to this.
1 : [a,b]
2 : [a,c]
..
Many thanks in Advance for any help!
dict = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
output = {}
for key, value in dict.items():
for v in value:
if v in output.keys():
output[v].append(key)
else:
output[v] = [ key ]
print(output)
And the output will be
{'2': ['a', 'c'], '1': ['a', 'b'], '5': ['b'], '3': ['c']}
before we go to the solution, lemme tell you something. What you've got there is not a nested dictionary but rather sets within the dictionary.
Some python terminologies to clear that up:
Array: [ 1 , 2 ]
Arrays are enclosed in square braces & separated by commas.
Dictionary: { "a":1 , "b":2 }
Dictionaries are enclosed in curly braces & separate "key":value pairs with comma. Here, "a" & "b" are keys & 1 & 2 would be their respective values.
Set: { 1 , 2 }
Sets are enclosed in curly braces & separated by commas.
dict = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
Here, {'1', '2'} is a set in a dictionary with key 'a'. Thus, what you've got is actually set in a dictionary & not a nested dictionary.
Solution
Moving on to the solution, sets are not iterable meaning you can't go through them one by one. So, you gotta turn them into lists & then iterate them.
# Initialize the dictionary to be processed
data = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
# Create dictionary to store solution
sol = {} # dictionary to store element as a key & sets containing that element as an array
# Eg., sol = { "1" : [ "a" , "b" ] }
# This shows that the value 1 is present in the sets contained in keys a & b.
# Record all elements & list every set containing those elements
for key in data. keys (): # iterate all keys in the dictionary
l = list ( data [ key ] ) # convert set to list
for elem in l: # iterate every element in the list
if elem in sol. keys (): # check if elem already exists in solution as a key
sol [ elem ]. append ( key ) # record that key contains elem
else:
sol [ elem ] = [ key ] # create a new list with elem as key & store that key contains elem
# At this time, sol would be
# {
# "1" : [ "a" , "b" ] ,
# "2" : [ "a" , "C" ] ,
# "3" : [ "c" ] ,
# "5" : [ "b" ]
# }
# Since, you want only the ones that are present in more than 1 sets, let's remove them
for key in sol : # iterate all keys in sol
if sol [ key ]. length < 2 : # Only keys in at least 2 sets will be retained
del sol [ key ] # remove the unrequired element
# Now, you have your required output in sol
print ( sol )
# Prints:
# {
# "1" : [ "a" , "b" ] ,
# "2" : [ "a" , "c" ]
# }
I hope that helps you...
You can use a defaultdict to build the output easily (and sort it if you want the keys in sorted order):
from collections import defaultdict
d = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
out = defaultdict(list)
for key, values in d.items():
for value in values:
out[value].append(key)
# for a sorted output (dicts are ordered since Python 3.7):
sorted_out = dict((k, out[k]) for k in sorted(out))
print(sorted_out)
#{'1': ['a', 'b'], '2': ['a', 'c'], '3': ['c'], '5': ['b']}
you can reverse the key-value in dict, create a value-key dict, if you only want duplicated values(find all the keys that have the same values), you can filter it:
from collections import defaultdict
def get_duplicates(dict1):
dict2 = defaultdict(list)
for k, v in dict1.items():
for c in v:
dict2[c].append(k)
# if you want to all values, just return dict2
# return dict2
return dict(filter(lambda x: len(x[1]) > 1, dict2.items()))
output:
{'1': ['a', 'b'], '2': ['a', 'c']}
This can be easily done using defaultdict from collections,
>>> d = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> for key,vals in d.items():
... for val in vals:
... dd[val].append(key)
...
>>>>>> dict(dd)
{'1': ['a', 'b'], '3': ['c'], '2': ['a', 'c'], '5': ['b']}
This can be easily achieved with two inner for loops:
dict = {'a': {'1','2'}, 'b':{'5','1'}, 'c':{'3','2'}}
out = {}
for key in dict:
for value in dict[key]:
if value not in out:
out[value]= [key]
else:
out[value]+= [key]
print out # {'1': ['a', 'b'], '3': ['c'], '2': ['a', 'c'], '5': ['b']}

RecursionError: maximum recursion depth exceeded while getting the repr of a list

I have 2 dictionaries as
new_dict = {'A' : {'C10' : 3, 'C11' : 4}, 'B' : {'C11' : 5, 'C12' : 6}}
and
new_dict1
(where key is a comma separated value).
i.e new_dict1 = { 'A,B' : {'C10' :4, 'C15' : 6}}
I want to create a new dictionary such that
dict_new = {'A' = [{'C10' :4, 'C15' : 6}, {'C10' : 3, 'C11' : 4}], 'B' = [{'C10' :4, 'C15' : 6}, {'C11' : 5, 'C12' : 6}]}
I tried with the following code. But its going in an infinite loop. Please help me out.
Code :
dict_new = {}
list_new = []
for k, v in new_dict1.items():
p = k.split(",")
for x in p:
list_new.append(v)
for s, t in new_dict.items():
if x == s:
list_new.append(t)
dict_new[x] = list_new
new_dict[x] = list_new
list_new = []
Here v and t are again dictionaries.
Thanks in advance

Duplicate values in a Python dictionary

I have a dictionary in the following format:
{ 'a' : [1], 'b' : [1,2,3], 'c' : [1,1,2], 'd' : [2,3,4] }
and I want to create a list of the keys which have a '1' in their values.
So my result list should look like:
['a','b','c','c']
I cannot understand how to work with duplicate values.
Any ideas how can I get such a list?
You can use list comprehensions
>>> d = { 'a' : [1], 'b' : [1,2,3], 'c' : [1,1,2], 'd' : [2,3,4] }
>>> [key for key, values in d.items() for element in values if element==1]
['c', 'c', 'b', 'a']
Here we have two nested for loops in our list comprehension. The first iterate over each key, values pairs in the dictionary and the second loop iterate over each element in the "value" list and return the key each time that element equal to 1. The result list is unordered because dict are unordered which means there are no guarantees about the order of the items.
Here is one way:
>>> x = { 'a' : [1], 'b' : [1,2,3], 'c' : [1,1,2], 'd' : [2,3,4] }
>>> list(itertools.chain.from_iterable([k]*v.count(1) for k, v in x.iteritems() if 1 in v))
['a', 'c', 'c', 'b']
If using Python 3, use items instead of iteritems.
This uses two loops, k,v in d.items() which gets each (key,value) pair from the dictionary, and n in v which loops through each value in v:
d = { 'a' : [1], 'b' : [1,2,3], 'c' : [1,1,2], 'd' : [2,3,4] }
l = []
for k,v in d.items():
for n in v:
if n == 1:
l.append(k)
l.sort()
If you want a one-liner:
l = sorted(k for k,v in d.items() for n in v if n == 1)
The sort must be made on the dictionary to get the expected result. This should work:
list = []
for i in sorted(d.keys()):
list+=[i for x in d[i] if x == 1]
print list
will output:
['a', 'b', 'c', 'c']
easy way: (Python 3)
d = { 'a' : [1], 'b' : [1,2,3], 'c' : [1,1,2], 'd' : [2,3,4] }
n = 1
result = []
for key, value in d.items():
for i in value.count(n):
res.append(key)
if you want list sorted than:
result.sort()

take a string as an input from the key of dictionary and return all the values in alphabetical order in Python

This function should take the first character from the key of a dictionary and return back all the keys in alphabetical order start with that first character without importing any files, when the method is:
def get_names_start(self,first_char,tools = None)
the dict looks like:
dict= {'Football' : 'BALL', 'Cricket' : 'BAT', 'Chess': 'CHESSBOARD'}
the output should be :
if we search by "C"
'Chess'
'Cricket'
d = {'Football': 'BALL', 'Cricket': 'BAT', 'Chess': 'CHESSBOARD'}
sorted([v for v in d if v.startswith("C")])
# => ['Chess', 'Cricket']
Here's one attempt
def f(ch="C"):
d= {'Football' : 'BALL', 'Cricket' : 'BAT', 'Chess': 'CHESSBOARD'}
ll = list()
for k in d:
if k[0] == ch:
ll.append(k)
return sorted(ll)
print f("C")
di= {'Football' : 'BALL', 'Cricket' : 'BAT', 'Chess': 'CHESSBOARD'}
def f(d,k):
return sorted( [ x for x in d.keys() if x.lower().startswith(k.lower())])
print(f(di,'c'))
['Chess', 'Cricket']

Categories