converting dictionary containing tuple to dictionary - python

I made a dictionary from textfile:
{('Aaronsburg', 'PA'): ('40.9184', '-77.3786'), ('Abbeville', 'AL'):
('31.5951', '-85.2108'), ('Abbeville', 'GA'): ('31.9890', '-83.3217'),
('Abbeville', 'LA'): ('29.9124', '-92.2110'), ('Abbeville', 'MS'):
('34.4771', '-89.4450'), ('Abbeville', 'SC'): ('34.1621', '-82.4333')}
These are sample from original text file:
Aaronsburg,PA,40.9184,-77.3786
Abbeville,AL,31.5951,-85.2108
and want to change all the tuple inside dictionary to dictionary like this:
{{'Aaronsburg', 'PA'}: {'40.9184', '-77.3786'}, {'Abbeville', 'AL'}:
{'31.5951', '-85.2108'}, {'Abbeville', 'GA'}: {'31.9890', '-83.3217'},
{'Abbeville', 'LA'}: {'29.9124', '-92.2110'}, {'Abbeville', 'MS'}:
{'34.4771', '-89.4450'}, {'Abbeville', 'SC'}: {'34.1621', '-82.4333'}}
but, got stuck while doing that....
This is original code till get dictionary
def coordinates(txt):
d = []
with open(txt) as f:
for line in f:
d.append(line.rstrip().split(','))
new_dict = {}
for sublist in d:
new_dict[tuple(sublist[:2])] = tuple(sublist[2:])
return((new_dict))

Dictionary keys need to be immutable. So, you can use frozenset instead of a set for keys and use set for values.
{frozenset(k):set(v) for k,v in my_dict.items()}
Output:
{frozenset({'Aaronsburg', 'PA'}): {'-77.3786', '40.9184'},
frozenset({'AL', 'Abbeville'}): {'-85.2108', '31.5951'},
frozenset({'Abbeville', 'GA'}): {'-83.3217', '31.9890'},
frozenset({'Abbeville', 'LA'}): {'-92.2110', '29.9124'},
frozenset({'Abbeville', 'MS'}): {'-89.4450', '34.4771'},
frozenset({'Abbeville', 'SC'}): {'-82.4333', '34.1621'}}

I think what your are trying to do is not possible, as a key cannot be from a mutable type. Reading python dictionary documentation dictionary documentation:
dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like append() and extend().

Related

How to index a list of dictionaries in python?

If I have a list of dictionaries in a python script, that I intend to later on dump in a JSON file as an array of objects, how can I index the keys of a specific dictionary within the list?
Example :
dict_list = [{"first_dict": "some_value"}, {"second_dict":"some_value"}, {"third_dict": "[element1,element2,element3]"}]
My intuitive solution was dict_list[-1][0] (to access the first key of the last dictionary in the list for example). This however gave me the following error:
IndexError: list index out of range
the key inputted into the dictionary will pick the some value in the format dict = {0:some_value}
to find a specific value:
list_dictionary = [{"dict1":'value1'},{"dict2","value2"}]
value1 = list_dictionary[0]["dict1"]
the 'key' is what you have to use to find a value from a dictionary
Example:
dictionary = {0:value}
dictionary[0]
in this case it will work
but to pick the elements we will do
values = []
for dictionary in dict_list:
for element in dictionary:
values.append(dictionary[element])
Output:
['some_value', 'some_value', ['element1', 'element2', 'element3']]
dict_list = [{"first_dict": "some_value"}, {"second_dict":"some_value"}, {"third_dict": ['element1','element2','element3']}]
If your dict look like this you can do as well
dict_list[-1]["third_dict"]
You can't access 'the first key' with a int since you have a dict
You can get the first key with .keys() and then
dict_list[-1].keys()[0]
By using dict_list[-1][0], you are trying to access a list with a list, which you do not have. You have a list with a dict key within a list.
Taking your example dict_list[-1][0]:
When you mention dict_list you are already "in the list".
The first index [-1] is referring to the last item of the list.
The second index would only be "usable" if the item mentioned in the previous index were a list. Hence the error.
Using:
dict_list=[{"first_dict": "some_value"}, {"second_dict":"some_value"},{"third_dict": [0,1,2]}]
to access the value of third_dict you need:
for value in list(dict_list[-1].values())[0]:
print(value)
Output:
0
1
2
If you know the order of dictionary keys and you are using one of the latest python versions (key stays in same order), so:
dict_list = [
{"first_dict": "some_value"}
, {"second_dict":"some_value"}
, {"third_dict": ["element1", "element2", "element3"]}
]
first_key = next(iter(dict_list[-1].keys()))
### OR: value
first_value = next(iter(dict_list[-1].values()))
### OR: both key and value
first_key, first_value = next(iter(dict_list[-1].items()))
print(first_key)
print(first_key, first_value)
print(first_value)
If you have the following list of dictionaries:
dict_list = [{"key1":"val1", "key2":"val2"}, {"key10":"val10"}]
Then to access the last dictionary you'd indeed use dict_list[-1] but this returns a dictionary with is indexed using its keys and not numbers: dict_list[0]["key1"]
To only use numbers, you'd need to get a list of the keys first: list(dict_list[-1]). The first element of this list list(dict_list[-1])[0] would then be the first key "key10"
You can then use indices to access the first key of the last dictionary:
dict_index = -1
key_index = 0
d = dict_list[dict_index]
keys = list(d)
val = d[keys[key_index]]
However you'd be using the dictionary as a list, so maybe a list of lists would be better suited than a list of dictionaries.

Change list according to dictionary items

Hello I have a list that looks like:
>>>ids
'70723295',
'75198124',
'140',
'199200',
'583561',
'71496270',
'69838760',
'70545907',
...]
I also have a dictionary that gives those numbers a 'name'. Now I want to create a new list that contains only the names, in the order like the numbers before.. so replace the numbers in the right order with the right names from the dictionary.
I tried:
with open('/home/anja/Schreibtisch/Master/ABA/alltogether/filelist.txt') as f:
ids = [line.strip() for line in f.read().split('\n')]
rev_subs = { v:k for v,k in dictionary.items()}
new_list=[rev_subs.get(item,item) for item in ids]
#dict looks like:
'16411': 'Itgax',
'241041': 'Gm4956',
'22419': 'Wnt5b',
'20174': 'Ruvbl2',
'71833': 'Dcaf7',
...}
But new_list is still the same as ids.
What am I doing wrong?
Maybe the dictionary keys are not in the format you think? Maybe the dictionary contains integers, meanwhile the ids are strings. I would investigate on that, it seems a mismatch of types more than an empty (or non-matching) dictionary.
Your dictionary keys are bs4.element.NavigableString objects rather than strings, so you cannot use strings as keys to look up its values.
You can fix this by converting the keys to strings when you build rev_subs:
rev_subs = {str(k): v for k, v in dictionary.items()}

Modify multiple keys of dictionary by a mapping dictionary

I have 2 dict, one original and one for mapping the original one's key to another value simultaneously,for instance:
original dict:
built_dict={'China':{'deportivo-cuenca-u20':{'danny':'test1'}},
'Germany':{'ajax-amsterdam-youth':{'lance':'test2'}}}
mapping dict:
club_team_dict={'deportivo-cuenca-u20':'deportivo','ajax-amsterdam-youth':'ajax'}
It works well if I use the following code to change the key of the nested dict of original dict,like
def club2team(built_dict,club_team_dict):
for row in built_dict:
# print test_dict[row]
for sub_row in built_dict[row]:
for key in club_team_dict:
# the key of club_team_dict must be a subset of test_dict,or you have to check it and then replace it
if sub_row==key:
built_dict[row][club_team_dict[sub_row]] = built_dict[row].pop(sub_row)
return built_dict
and the result:
{'Germany': {'ajax': {'lance': 'test2'}}, 'China': {'deportivo': {'danny': 'test1'}}}
so far so good, however if I have a dict with multiple key mapping to the same key,for example,my original dict is like
built_dict={'China':{'deportivo-cuenca-u20':{'danny':'test1'}},
'Germany':{'ajax-amsterdam-youth':{'lance':'test2'},
'ajax-amsterdam':{'tony':'test3'}}}
and the mapping dict with more then 1 key mapping to the same value,like:
club_team_dict={'deportivo-cuenca-u20':'deportivo',
'ajax-amsterdam-youth':'ajax',
'ajax-amsterdam':'ajax'}
as you can see, both 'ajax-amsterdam-youth'and 'ajax-amsterdam-youth' are mapping to 'ajax',and the trouble is when I use the same code to execute it, the original dict's size has been changed during the iteration
RuntimeError: dictionary changed size during iteration
I want to get a result with nested list for the same key like this
{'Germany': {'ajax':[{'lance': 'test2'},
{'tony' : 'test3'}]}},
'China': {'deportivo': [{'danny': 'test1'}]}}
Well I have found a solution for this,the code:
def club2team(built_dict,club_team_dict):
for row in built_dict:
# print test_dict[row]
for sub_row in built_dict[row].keys():
for key in club_team_dict:
# the key of club_team_dict must be a subset of test_dict,or you have to check it and then replace it
if sub_row==key:
# built_dict[row][club_team_dict[sub_row]] = built_dict[row].pop(sub_row)
built_dict[row].setdefault(club_team_dict[sub_row],[]).append(built_dict[row].pop(sub_row))
return built_dict
pay attention to the for sub_row in built_dict[row].keys(): and setdefault() method, I used to believe that in python 2.7, the default iteration for dict is just iterate the keys(), however, this time it proves it's a little different, maybe you have better solution, please show me and it will be appreciate,thank you

clearing a dictionary but keeping the keys

Is it possible to clear all the entries within a dictionary but keep all the keys?
For example if I had:
my_dic={
"colour":[],
"number":[]
}
I put some stuff in them:
my_dic["colour"]='Red'
my_dic["number"]='2'
I can clear these by:
my_dic["colour"] = []
my_dic["number"] = []
But this is long winded if I want to clear a large dictionary quickly, is there a quicker way perhaps using for? I want to keep the keys ["colour"], ["number"], without having to recreate them, just clear all the entries within them.
You can simply clear all lists in a loop:
for value in my_dic.values():
del value[:]
Note the value[:] slice deletion; we are removing all indices in the list, not the value reference itself.
Note that if you are using Python 2 you probably want to use my_dic.itervalues() instead of my_dic.values() to avoid creating a new list object for the loop.
Demo:
>>> my_dic = {'colour': ['foo', 'bar'], 'number': [42, 81]}
>>> for value in my_dic.values():
... del value[:]
...
>>> my_dic
{'colour': [], 'number': []}
You could also replace all values with new empty lists:
my_dic.update((key, []) for key in my_dic)
or replace the whole dictionary entirely:
my_dic = {key: [] for key in my_dic}
Take into account these two approaches will not update other references to either the lists (first approach) or the whole dictionary (second approach).
You no need to delete keys from dictionary:
for key in my_dict:
my_dict[key] = []
One liner:
my_dict = dict.fromkeys(my_dict, None)
You can also replace the None type with other values that are immutable. A mutable type such as a list will cause all of the values in your new dictionary to be the same list.
For mutable types you would have to populate the dictionary with distinct instances of that type as others have shown.

Converting dict values into a set while preserving the dict

I have a dict like this:
(100002: 'APPLE', 100004: 'BANANA', 100005: 'CARROT')
I am trying to make my dict have ints for the keys (as it does now) but have sets for the values (rather than strings as it is now.) My goal is to be able to read from a .csv file with one column for the key (an int which is the item id number) and then columns for things like size, shape, and color. I want to add this information into my dict so that only the information for keys already in dict are added.
My goal dict might look like this:
(100002: set(['APPLE','MEDIUM','ROUND','RED']), 100004: set(['Banana','MEDIUM','LONG','YELLOW']), 100005: set(['CARROT','MEDIUM','LONG','ORANGE'])
Starting with my dict of just key + string for item name, I tried code like this to read the extra information in from a .csv file:
infile = open('FileWithTheData.csv', 'r')
for line in infile.readlines():
spl_line = line.split(',')
if int(spl_line[0]) in MyDict.keys():
MyDict[int(spl_line[0])].update(spl_line[1:])
Unfortunately this errors out saying AttributeError: 'str' object has no attribute 'update'. My attempts to change my dictionary's values into sets so that I can then .update them have yielded things like this: (100002: set(['A','P','L','E']), 100004: set(['B','A','N']), 100005: set(['C','A','R','O','T']))
I want to convert the values to a set so that the string that is currently the value will be the first string in the set rather than breaking up the string into letters and making a set of those letters.
I also tried making the values a set when I create the dict by zipping two lists together but it didn't seem to make any difference. Something like this
MyDict = dict(zip(listofkeys, set(listofnames)))
still makes the whole listofnames list into a set but it doesn't achieve my goal of making each value in MyDict into a set with the corresponding string from listofnames as the first string in the set.
How can I make the values in MyDict into a set so that I can add additional strings to that set without turning the string that is currently the value in the dict into a set of individual letters?
EDIT:
I currently make MyDict by using one function to generate a list of item ids (which are the keys) and another function which looks up those item ids to generate a list of corresponding item names (using a two column .csv file as the data source) and then I zip them together.
ANSWER:
Using the suggestions here I came up with this solution. I found that the section that has set()).update can easily be changed to list()).append to yield a list rather than a set (so that the order is preserved.) I also found it easier to update by .csv data input files by adding the column containing names to the FileWithTheData.csv so that I didn't have to mess with making the dict, converting the values to sets, and then adding in more data. My code for this section now looks like this:
MyDict = {}
infile = open('FileWithTheData.csv', 'r')
for line in infile.readlines():
spl_line = line.split(',')
if int(spl_line[0]) in itemidlist: #note that this is the list I was formerly zipping together with a corresponding list of names to make my dict
MyDict.setdefault(int(spl_line[0]), list()).append(spl_line[1:])
print MyDict
Your error is because originally your MyDict variable maps an integer to a string. When you are trying to update it you are treating the value like a set, when it is a string.
You can use a defaultdict for this:
combined_dict = defaultdict(set)
# first add all the values from MyDict
for key, value in MyDict.iteritems():
combined_dict[int(key)].add(value)
# then add the values from the file
infile = open('FileWithTheData.csv', 'r')
for line in infile.readlines():
spl_line = line.split(',')
combined_dict[int(sp_line[0])].update(spl_line[1:])
Your issue is with how you are initializing MyDict, try changing it to the following:
MyDict = dict(zip(listofkeys, [set([name]) for name in listofnames]))
Here is a quick example of the difference:
>>> listofkeys = [100002, 100004, 100005]
>>> listofnames = ['APPLE', 'BANANA', 'CARROT']
>>> dict(zip(listofkeys, set(listofnames)))
{100002: 'CARROT', 100004: 'APPLE', 100005: 'BANANA'}
>>> dict(zip(listofkeys, [set([name]) for name in listofnames]))
{100002: set(['APPLE']), 100004: set(['BANANA']), 100005: set(['CARROT'])}
set(listofnames) is just going to turn your list into a set, and the only effect that might have is to reorder the values as seen above. You actually want to take each string value in your list, and convert it to a one-element set, which is what the list comprehension does.
After you make this change, your current code should work fine, although you can just do the contains check directly on the dictionary instead of explicitly checking the keys (key in MyDict is the same as key in MyDict.keys()).

Categories