Iterators in Python dict - python

Here is a simple nested dictionary:
wordFrequency = {'bit':{1:3,2:4,3:19,4:0},'red':{1:0,2:0,3:15,4:0},'dog':{1:3,2:0,3:4,4:5}}
I am trying to work out the difference between what these two pieces of code do:
for word, innerDictionary in wordFrequency.iteritems():
for fileNum, appearances in innerDictionary.iteritmes():
and
for fileNum, appearances in wordFrequency.get(word, {}).iteritems():
I know the first allows me to assign the keys and values of the inner dictionary to fileNum and appearances respectively.
However, I am unclear as to if the second piece of code does the same?

The following command :
for fileNum, appearances in wordFrequency.get(word, {}).iteritems():
Will give you only one value (of nested dictionaries) , but if you want it have a same effect like your preceding code ,As the get()'s function first argument must be a key of the dictionary you need to get the keys and put that code in a loop :
for word in wordFrequency.keys() :
for fileNum, appearances in wordFrequency.get(word, {}).iteritems():

Related

Why does iterating through two dictionaries in python yield strange results?

I am iterating through the keys of one dictionary, finding the same key in a second dictionary, then trying to produce the first value of the list associated with the key in the second dictionary. When I look directly into the second dictionary it works fine:
Code:
for data in hud_data.get('veh_1'):
print(data[0])
Returns:
17.3245
This is correct. But when I try to run through all of the keys of hud_data by referencing the keys of another dictionary (UAV_data), I get a strange result:
Code:
for a_key in UAV_dict.keys():
# print(a_key)
for data in hud_data.get(a_key):
print(data[0])
break
This should produce the exact same thing. The first key in UAV_dict is 'veh_1', so when the second for loop runs, it should just return the same thing, 17.3245. Instead it returns all of the values for every key:
Return:
17.3245
19.3003
22.2483
29.8077
35.86
Why are all of the values for every key showing up in the output? How should I re-write the code so that it only produces the first outcome?
Your break statement only stops the inner for-loop. The other loop on UAV_dict.keys() is not affected

Python: Randomly Select One Key From All Keys in a Dictionary

Let's say I have accessed my dictionary keys using print (hamdict.keys())
Below is a sample output:
I know my dictionary list has a length of 552 elements. I want to randomly select one "key" word from my list and assign it to the variable "starter". I tried to do this with the code below (note: I have a dictionary called hamdict):
random_num = random.randint(0, len(hamdict.keys())-1)
print (random_num)
print (hamdict.keys()[random_num])
I'm able to get a value for random_num so that seems to work. But the second print returns the following error:
How can I fix my code?
my_dictionary.keys() returns a generator-like object, not a list. You can probably get what you want by converting it to a list first
print(list(hamdict.keys())[random_num])
Try this:
random.sample(hamdict.keys(),1)[0]
The sample() function randomly selects a given number of items from a list or iterator. Contrary to the choice function, it supports iterators so you don't need to make a list out of the keys beforehand. The result is a list so you need to get its first item from the output (hence the [0]).

How to compare a python dictionary key with a part of another dictionary's key? something like a .contains() function

Most of my small-scale project worked fine using dictionaries, so changing it now would basically mean starting over.
Let's say I have two different dictionaries(dict1 and dict2).
One being:
{'the dog': 3, 'dog jumped': 4, 'jumped up': 1, 'up onto': 8, 'onto me': 13}
Second one being:
{'up': 12, 'dog': 22, 'jumped': 33}
I want to find wherever the first word of the first dictionary is equal to the word of the second one. These 2 dictionaries don't have the same length, like in the example. Then after I find them, divide their values.
So what I want to do, sort of using a bit of Java is:
for(int i = 0;i<dict1.length(),i++){
for(int j = 0;j<dict2.length(),j++){
if(dict1[i].contains(dict2[j]+" ") // not sure if this works, but this
// would theoretically remove the
// possibility of the word being the
// second part of the 2 word element
dict1[i] / dict2[j]
What I've tried so far is trying to make 4 different lists. A list for dict1 keys, a list for dict1 values and the same for dict2. Then I've realized I don't even know how to check if dict2 has any similar elements to dict1.
I've tried making an extra value in the dictionary (a sort of index), so it would kind of get me somewhere, but as it turns out dict2.keys() isn't iterable either. Which would in turn have me believe using 4 different lists and trying to compare it somehow using that is very wrong.
Dictionaries don't have any facilities at all to handle parts of keys. Keys are opaque objects. They are either there or not there.
So yes, you would loop over all the keys in the first dictionary, extract the first word, and then test if the other dictionary has that first word as a key:
for key, dict1_value in dict1.items():
first_word = key.split()[0] # split on whitespace, take the first result
if first_word in dict2:
dict2_value = dict2[first_word]
print(dict1_value / dict2_value)
So this takes every key in dict1, splits off the first word, and tests if that word is a key in dict2. If it is, get the values and print the result.
If you need to test those first words more often, you could make this a bit more efficient by first building another structure to to create an index from first words to whole keys. Simply store the first words every key of the first dictionary, in a new dictionary:
first_to_keys = {}
for key in dict1:
first_word = key.split()[0]
# add key to a set for first_word (and create the set if there is none yet)
first_to_keys.setdefault(first_word, set()).add(key)
Now first_to_key is a dictionary of first words, pointing to sets of keys (so if the same first word appears more than once, you get all full keys, not just one of them). Build this index once (and update the values each time you add or remove keys from dict1, so keep it up to date as you go).
Now you can compare that mapping to the other dictionary:
for matching in first_to_key.keys() & dict2.keys():
dict2_value = dict2[matching]
for dict1_key in first_to_key[matching]:
dict1_value = dict1[dict1_key]
print(dict1_value / dict2_value)
This uses the keys from two dictionaries as sets; the dict.keys() object is a dictionary view that lets you apply set operations. & gives you the intersection of the two dictionary key sets, so all keys that are present in both.
You only need to use this second option if you need to get at those first words more often. It gives you a quick path in the other direction, so you could loop over dict2, and quickly go back to the first dictionary again.
Here's a solution using the str.startswith method of strings
for phrase, val1 in dict1.items():
for word, val2 in dict2.items():
if phrase.startswith(word):
print(val1/val2)

Slicing strings in a comprehension

I'm I need to slice the leading character off the valued a dictionary - but only if the length of the value is greater than 1. Currently I'm doing this with a dictionary comprehension:
new_dict = {item[0]:item[1][1:] for item in old_dict if item.startswith('1')}
but I don't know how to modify this so that keys of length one are left alone.
The keys are the codewords of a Huffman code, and so start with '0' or '1'.
An example code is:
code = {'a':'0', 'b':'10', 'c':'110', 'd':'111'}
The above code works fine for 'b','c','d' but fails for 'a' (this is intensional - it's a unit test).
How do I correctly modify the above example to pass the test?
The nature of a comprehension is that it builds a new object iteratively, so you if you want every key in the original object old_dict to have a corresponding key in new_dict, you simply have to process every key.
Also, you say "I need to slice the leading character off the keys a dictionary", but the code you give slices the leading characters off the values. I assume you mean values. I suggest the following:
new_dict = {key:(value[:1] if len(value) > 1 else value) for key,value in old_dict.iteritems()}
Apart from using sequence assignment to make the iteration a bit clearer, I've used the if expression (equivalent to ternary operator in c-like languages) to incorporate the condition.
I've also dropped your original if clause, because I don't understand you to want to skip values starting with '1'.
I'm not sure which variable is where but you could do something along these lines.
new_dict = { item[0]:item[1][1] if len(item[1]) > 1 else item[0]:item[1] for item in old_dict if item.startswith('1') }
If I understand your question correctly, you can accomplish it with this:
new_dict = {k:v[len(v)>1:] for k,v in old_dict.items()}
v[len(v)>1] will return the key if it is only 1 character, and it will strip off the leading character if it is more than one character
I'm not sure what you are trying to accomplish with if item.startswith('1') is a qualifier for your list comprehension but if you need it you can add it back on. May need to make it v.startswith('1') though.

Removing one element from an entire dictionary

I've been working on this thing for hours, still cant figure it out :O
The problem I'm having is this. Lets say I have a dictionary with 4-element tuples as elemets and an integer as key. When an element is removed from the whole dictionary (which belongs to every tuple) making two of the tuples (elements) same, the keys of the two tuples don't add up. Instead, a new element is formed, with the key for that element being one of the previous 2 keys.
Let's say I have a dictionary:
dict={('A','B','D','C'): 4, ('C','B','A','D'):5, ('D','A','C','B'):3,('D','A','B','C'):1}
Now I wanna remove one letter from the entire dictionary.
for example, If I wanna remove 'B'. The following new dictionary is formed, but isn't returned, because two of the elements are the same.
{('A','D','C'): 4, ('C','A','D'):5, ('D','A','C'):3,('D','A','C'):1}
Instead of ('D','A','C'):3,('D','A','C'):1 becoming ('D','A','C'):4, this is what ends up happenening:
('D','A','C'):3 along with other tuples
So basically, one of the tuples disappears.
This is the method I'm currently using:
for next in dict:
new_tuple=()
for i in next:
if i!='A':
new_tuple+=(i,)
new_dict[new_tuple]=dict[next]
The above code returns new_dict as the following:
{('A','D','C'): 4, ('C','A','D'):5, ('D','A','C'):3}
So what can I do, to remove one letter from every tuple in the entire dictionary, and if two of the tuples look the same, they merge and the keys add up?
You will have to rebuild your entire dictionary, as each key/value pair is going to be affected. You can use a defaultdict to make the merging easier when you encounter now-overlapping keys:
from collections import defaultdict
new_dict = defaultdict(int)
for key, value in old_dict.items():
new_key = tuple(i for i in key if i != 'A')
new_dict[new_key] += value
Because when first looking up new_key in new_dict it'll be set to 0 by default, all we have to do is add the old value to update new_dict for when we first encounter a key. The next time we encounter the key the values are 'merged' by adding them up.

Categories

Resources