How to get the following dictionary in tne easiest way? - python

I get a list here:
my_list=["Alex:1990:London",
"Tony:1993:NYC",
"Kate:2001:Beijing",
"Tony:2001:LA",
"Alex:1978:Shanghai"]
How can I get the target dictionary my_target_dict from my_list in the easiest way?
my_target_dict={
"Alex":["Alex:1990:London", "Alex:1978:Shanghai"],
"Tony":["Tony:1993:NYC", "Tony:2001:LA"],
"Kate":["Kate:2001:Beijing"]
}

Use a defaultdict:
>>> from collections import defaultdict
>>> my_list=["Alex:1990:London", "Tony:1993:NYC", "Kate:2001:Beijing", "Tony:2001:LA", "Alex:1978:Shanghai"]
>>> d = defaultdict(list)
>>> for item in my_list:
... name, *_ = item.partition(":")
... d[name].append(item)
...
>>> d
defaultdict(<class 'list'>, {'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']})
>>> d["Alex"]
['Alex:1990:London', 'Alex:1978:Shanghai']
You can use this comprehension to clean the list wrapped single items:
>>> {k:v if len(v) > 1 else v[0] for k,v in d.items()}
{'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': 'Kate:2001:Beijing'}

In case you intend to work strictly with lists and dictionaries alone, try this:
my_target_dict=dict()
for value in my_list:
key=value.split(':')[0]
if key in my_target_dict:
my_target_dict[key].append(value)
else:
my_target_dict[key]=[value]
print(my_target_dict)

This is my solution for you:
my_list=["Alex:1990:London", "Tony:1993:NYC", "Kate:2001:Beijing", "Tony:2001:LA", "Alex:1978:Shanghai"]
dict = {}
for idx, content in enumerate(my_list):
name = content[:(content.index(':'))]
if name not in dict:
dict[name] = []
dict[name].append(my_list[idx])
First if you don't know about enumerate, it count your index and
take the content in each element of list.
Second, take name of there people by basic python of string. I use name = content[:(content.index(':'))] in order to take string from start to the first symbol ":".
Third, check if the key of dict exist or not. Otherwise, it will delete all your element in list of that key.
Last but not least, append the element you want into your key dict.
Your finally result:
{'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']}

If you are a beginner (as I see) and don't want to use Python's collections module and do the implementation from scratch (it's imp to understand the concept of background work which collection does).
Once you are familiar with this, you can go with collections module and that is beautiful as it has many classes like defaultdict, OrderedDict etc. which can boost the speed of your work.
Here is what I have tried (do not forget to read the commented lines).
I have written a function named get_my_target_dict() which takes my_list and returns my_target_dict. And this is the modular implemenation (that you should prefer).
re is a module to work with regular expressions. Here it is used to match "Alex: 1990 : London" (i.e. spaces around :) kind of strings if any (by mistake).
import re
def get_my_target_dict(my_list):
my_target_dict = {} # dictionary
for string in my_list:
# "Alex:1990:London" => ["Alex", "1990", "London"]
# "Alex : 1990: London" => ["Alex", "1990", "London"]
items = re.split(r"\s*:\s*", string) # `\s*` is to match spaces around `:`
print(items)
# Alex, Tony etc.
key = items[0]
if key in my_target_dict:
my_target_dict[key].append(string)
else:
my_target_dict[key] = [string]
return my_target_dict
if __name__ == "__main__":
my_list=["Alex:1990:London",
"Tony:1993:NYC",
"Kate:2001:Beijing",
"Tony:2001:LA",
"Alex:1978:Shanghai"]
# Call get_my_target_dict(), pass my_list & get my_target_dict
my_target_dict = get_my_target_dict(my_list)
print(my_target_dict)
# {'Alex': ['Alex:1990:London', 'Alex:1978:Shanghai'], 'Tony': ['Tony:1993:NYC', 'Tony:2001:LA'], 'Kate': ['Kate:2001:Beijing']}
# Pretty printing dictionary
import json
print(json.dumps(my_target_dict, indent=4))
# {
# "Alex": [
# "Alex:1990:London",
# "Alex:1978:Shanghai"
# ],
# "Tony": [
# "Tony:1993:NYC",
# "Tony:2001:LA"
# ],
# "Kate": [
# "Kate:2001:Beijing"
# ]
# }

Related

how can i loop like this but getting everything instead of only the 1st one

i want loop like this but getting everything instead of only the 1st one.
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID","3ndID"], 'ChannelID': ["1stChannel", "2ndChannel","3ndChannel"]
})
first_values = [v[0] for v in myList.values()]
print(first_values)
OUTPUT
['1stID', '1stChannel']
instead of
['1stID', '1stChannel']
DESIRED OUTPUT:
['1stID', '1stChannel']
['2stID', '2stChannel']
['3stID', '3stChannel']
You can use zip() to combine two list and get the combined pairs, as follows:
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID", "3ndID"],
'ChannelID': ["1stChannel", "2ndChannel", "3ndChannel"]
})
pairs = zip(myList['ID'], myList['ChannelID'])
# list(pairs) -> [('1stID', '1stChannel'), ('2ndID', '2ndChannel'), ('3ndID', '3ndChannel')]
for pair in pairs:
print(list(pair))
Result:
['1stID', '1stChannel']
['2ndID', '2ndChannel']
['3ndID', '3ndChannel']
Other method (if you don't want to use key names):
from collections import OrderedDict
myList = OrderedDict(
{
"ID": ["1stID", "2ndID", "3ndID"],
"ChannelID": ["1stChannel", "2ndChannel", "3ndChannel"],
}
)
for a in zip(*myList.values()):
print(a) # or list(a) for lists instead of tuples
Prints:
('1stID', '1stChannel')
('2ndID', '2ndChannel')
('3ndID', '3ndChannel')
You misunderstood the structure you are building so you are not accessing it correctly.
mylist is a 2 element dictionary. each of the element are lists of length 3.
There is no connection between the positional elements of each other than the position.
See code below how I extracted and printed the data.
There may be an idiomatic way to do this in python more cleanly
but this served to show the structure clearly.
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID", "3ndID"],
'ChannelID': ["1stChannel", "2ndChannel", "3ndChannel"]
})
first_values = [v[0] for v in myList.values()]
print(first_values)
#
# print out the values of the objects in the list
for v in myList.values():
print(v)
# extract the two lists
vid, vchan = myList.values()
# print out the whole list in one statement
print("all of vid ", vid)
print("all of vchan ", vchan)
# print out the element of the lists position by position
for i in range(len(vid)):
print(i, "th list item ", vid[i], vchan[i])

Is it possible for a key to have multiple names in a dictionary?

I'm not sure if this is even possible but it's worth a shot asking.
I want to be able to access the value from indexing one of the values.
The first thing that came to mind was this but of course, it didn't work.
dict = {['name1', 'name2'] : 'value1'}
print(dict.get('name1))
You can use a tuple (as it's immutable) as a dict key if you need to access it by a pair (or more) of strings (or other immutable values):
>>> d = {}
>>> d[("foo", "bar")] = 6
>>> d[("foo", "baz")] = 8
>>> d
{('foo', 'bar'): 6, ('foo', 'baz'): 8}
>>> d[("foo", "baz")]
8
>>>
This isn't "a key having multiple names", though, it's just a key that happens to be built of multiple strings.
Edit
As discussed in the comments, the end goal is to have multiple keys for each (static) value. That can be succinctly accomplished with an inverted dict first, which is then "flipped" using dict.fromkeys():
def foobar():
pass
def spameggs():
pass
func_to_names = {
foobar: ("foo", "bar", "fb", "foobar"),
spameggs: ("spam", "eggs", "se", "breakfast"),
}
name_to_func = {}
for func, names in func_to_names.items():
name_to_func.update(dict.fromkeys(names, func))
If we tried it you way using:
# Creating a dictionary
myDict = {[1, 2]: 'Names'}
print(myDict)
We get an output of:
TypeError: unhashable type: 'list'
To get around this, we can use this method:
# Creating an empty dictionary
myDict = {}
# Adding list as value
myDict["key1"] = [1, 2]
myDict["key2"] = ["Jim", "Jeff", "Jack"]
print(myDict)

Nested lists to nested dicts

I've a list with master keys and a list of list of lists, where the first value of each enclosed list (like 'key_01') shall be a sub key for the corresponding values (like 'val_01', 'val_02'). The data is shown here:
master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
I would like these lists to be combined into a dictionary of dictionaries, like this:
master_dic = {
"Master_01": {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
"Master_02": {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
"Master_03": {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
What I've got so far is the sub dict:
import itertools
master_dic = {}
servant_dic = {}
keys = []
values = []
for line in data_long:
for item in line:
keys.extend(item[:1])
values.append(item[1:])
servant_dic = dict(itertools.izip(keys, values))
Which puts out a dictionary, as expected.
servant_dic = {
'key_06': ['val_11','val_12'], 'key_04': ['val_08','val_07'], 'key_05': ['val_09','val_10'],
'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06'], 'key_01': ['val_01','val_02']
}
The problem is, that if I want to add the master_keys to this dictionary, so I get the wanted result, I'd have to do this in a certain order, which would be possible, if each line had a counter like this:
enumerated_dic =
{
0: {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
1: {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
2: {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
I'd love to do this with enumerate(), while each line of the servant_dic is build, but can't figure out how. Since afterwards, i could simply replace the counters 0, 1, 2 etc. with the master_keys.
Thanks for your help.
master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
_dict = {}
for master_key, item in zip(master_keys, data_long):
_dict[master_key] = {x[0]: x[1:] for x in item}
print _dict
Hope this will help:
{master_key: {i[0]: i[1:] for i in subkeys} for master_key, subkeys in zip(master_keys, data_long)}
My functional approach:
master_dic = dict(zip(master_keys, [{k[0]: k[1::] for k in emb_list} for emb_list in data_long]))
print(master_dic)
You can also use pop and a dict comprehension:
for key, elements in zip(master_keys, data_long):
print {key: {el.pop(0): el for el in elements}}
...:
{'Master_01': {'key_02': ['val_03', 'val_04'], 'key_03': ['val_05', 'val_06']}}
{'Master_02': {'key_06': ['val_11', 'val_12'], 'key_04': ['val_07', 'val_08'], 'key_05': ['val_09', 'val_10']}}
{'Master_03': {'key_07': ['val_13', 'val_14'], 'key_08': ['val_15', 'val_16'], 'key_09': ['val_17', 'val_18']}}

Dictionary out of a list in python

I want to create a dictionary out of a list that has several similar elements. But, in the dictionary, all these similar elements must have the same key.
d_dict={}
lst=['A1','A2','A3','2e','2o','2m']
for element in lst:
if element.startswith('A'):
d_dict[1].append(element)
elif element.startswith('2'):
d_dict[2].append(element)
print(d_dict)
My output should look like:
d_dict={1:['A1','A2','A3'],2:['2e','2o','2m']}
thanks.
You're looking for collections.defaultdict:
>>> from collections import defaultdict
>>> d_dict = defaultdict(list)
>>> for element in lst:
... if element.startswith('A'):
... d_dict[1].append(element)
... elif element.startswith('2'):
... d_dict[2].append(element)
...
>>> print d_dict
defaultdict(<type 'list'>, {1: ['A1', 'A2', 'A3'], 2: ['2e', '2o', '2m']})
So pretty much, with this module, your code is exactly the same. You only need to make your dictionary a type defaultdict so that you can have lists as values without having to create any.
You need to create the lists before appending something to them:
for element in lst:
if element.startswith('A'):
if 1 not in d_dict: # if it is not already created
d_dict[1] = [element] # add list with the current element
else:
d_dict[1].append(element)
elif element.startswith('2'):
if 2 not in d_dict:
d_dict[2] = [element]
else:
d_dict[2].append(element)
The only problem I see in your code is that you don't initialize the sublists, so d_dict[1] doesn't exist. But you can avoid having to do this altogether if you use a defaultdict.
from collections import defaultdict
d_dict=defaultdict(list)
d_dict[1].extend(e for e in lst if e.startswith('A'))
d_dict[2].extend(e for e in lst if e.startswith('2'))
If you wanted your code to be more flexible, this will work with any strings, not just those starting with A and 2. You can use the defaultdict class from collections.
from collections import defaultdict
values = ['A1','A2','A3','2e','2o','2m']
grouped = defaultdict(list)
for i in values:
grouped[i[0]].append(i)
print(dict(grouped))

Removing nested dict items with dict comprehension

I have two dicts:
blocked = {'-5.00': ['121', '381']}
all_odds = {'-5.00': '{"121":[1.85,1.85],"381":[2.18,1.73],"16":[2.18,1.61],"18":\
[2.12,1.79]}'}
I want to first check whether the .keys() comparision (==) returns True, here it does (both -5.00) then I want to remove all items from all_odds that has the key listed in blocked.values() .
For the above it should result in:
all_odds_final = {'-5.00': '{"16":[2.18,1.61],"18": [2.12,1.79]}'}
I tried for loop:
if blocked.keys() == all_odds.keys():
for value in blocked.values():
for v in value:
for val in all_odds.values():
val = eval(val)
if val.has_key(v):
del val[v]
which you know is very ugly plus it's not working properly yet.
First, make the string a dictionary with ast.literal_eval(). Don't use eval():
>>> import ast
>>> all_odds['-5.00'] = ast.literal_eval(all_odds['-5.00'])
Then you can use a dictionary comprehension:
>>> if blocked.keys() == all_odds.keys():
... print {blocked.keys()[0] : {k:v for k, v in all_odds.values()[0].iteritems() if k not in blocked.values()[0]}}
...
{'-5.00': {'18': [2.12, 1.79], '16': [2.18, 1.61]}}
But if you want the value of -5.00 as a string...
>>> {blocked.keys()[0]:str({k: v for k, v in all_odds.values()[0].iteritems() if k not in blocked.values()[0]})}
{'-5.00': "{'18': [2.12, 1.79], '16': [2.18, 1.61]}"}
Here's how you can do the same in about 2 lines. I'm not going to use ast, or eval here, but you can add that if you want to use that.
>>> blocked = {'-5.00': ['121', '381']}
>>> all_odds = {'-5.00': {'121':[1.85,1.85],'381':[2.18,1.73],'16':[2.18,1.61],'18':\
... [2.12,1.79]}}
>>> bkeys = [k for k in all_odds.keys() if k in blocked.keys()]
>>> all_odds_final = {pk: {k:v for k,v in all_odds.get(pk).items() if k not in blocked.get(pk)} for pk in bkeys}
>>> all_odds_final
{'-5.00': {'18': [2.12, 1.79], '16': [2.18, 1.61]}}
This seems to work:
blocked = {'-5.00': ['121', '381']}
all_odds = {'-5.00': {"121":[1.85,1.85],"381":[2.18,1.73],"16":[2.18,1.61],"18":\
[2.12,1.79]}}
all_odds_final = dict(all_odds)
for key, blocks in blocked.iteritems():
map(all_odds_final[key].pop,blocks,[])
If you do not want to copy the dictionary, you can just pop items out of the original all_odds dictionary:
for key, blocks in blocked.iteritems():
map(all_odds[key].pop,blocks,[])
The empty list in the map function is so pop gets called with None as it's second argument. Without it pop only gets one argument and will return an error if the key is not present.

Categories

Resources