How to index into a dictionary? - python

I have a Dictionary below:
colors = {
"blue" : "5",
"red" : "6",
"yellow" : "8",
}
How do I index the first entry in the dictionary?
colors[0] will return a KeyError for obvious reasons.

If anybody is still looking at this question, the currently accepted answer is now outdated:
Since Python 3.7*, dictionaries are order-preserving, that is they now behave like collections.OrderedDicts. Unfortunately, there is still no dedicated method to index into keys() / values() of the dictionary, so getting the first key / value in the dictionary can be done as
first_key = list(colors)[0]
first_val = list(colors.values())[0]
or alternatively (this avoids instantiating the keys view into a list):
def get_first_key(dictionary):
for key in dictionary:
return key
raise IndexError
first_key = get_first_key(colors)
first_val = colors[first_key]
If you need an n-th key, then similarly
def get_nth_key(dictionary, n=0):
if n < 0:
n += len(dictionary)
for i, key in enumerate(dictionary.keys()):
if i == n:
return key
raise IndexError("dictionary index out of range")
* CPython 3.6 already included insertion-ordered dicts, but this was only an implementation detail. The language specification includes insertion-ordered dicts from 3.7 onwards.

Dictionaries are unordered in Python versions up to and including Python 3.6. If you do not care about the order of the entries and want to access the keys or values by index anyway, you can create a list of keys for a dictionary d using keys = list(d), and then access keys in the list by index keys[i], and the associated values with d[keys[i]].
If you do care about the order of the entries, starting with Python 2.7 you can use collections.OrderedDict. Or use a list of pairs
l = [("blue", "5"), ("red", "6"), ("yellow", "8")]
if you don't need access by key. (Why are your numbers strings by the way?)
In Python 3.7, normal dictionaries are ordered, so you don't need to use OrderedDict anymore (but you still can – it's basically the same type). The CPython implementation of Python 3.6 already included that change, but since it's not part of the language specification, you can't rely on it in Python 3.6.

Addressing an element of dictionary is like sitting on donkey and enjoy the ride.
As a rule of Python, a DICTIONARY is orderless
If there is
dic = {1: "a", 2: "aa", 3: "aaa"}
Now suppose if I go like dic[10] = "b", then it will not add like this always
dic = {1:"a",2:"aa",3:"aaa",10:"b"}
It may be like
dic = {1: "a", 2: "aa", 3: "aaa", 10: "b"}
Or
dic = {1: "a", 2: "aa", 10: "b", 3: "aaa"}
Or
dic = {1: "a", 10: "b", 2: "aa", 3: "aaa"}
Or any such combination.
So a rule of thumb is that a DICTIONARY is orderless!

If you need an ordered dictionary, you can use odict.

oh, that's a tough one. What you have here, basically, is two values for each item. Then you are trying to call them with a number as the key. Unfortunately, one of your values is already set as the key!
Try this:
colors = {1: ["blue", "5"], 2: ["red", "6"], 3: ["yellow", "8"]}
Now you can call the keys by number as if they are indexed like a list. You can also reference the color and number by their position within the list.
For example,
colors[1][0]
// returns 'blue'
colors[3][1]
// returns '8'
Of course, you will have to come up with another way of keeping track of what location each color is in. Maybe you can have another dictionary that stores each color's key as it's value.
colors_key = {'blue': 1, 'red': 6, 'yllow': 8}
Then, you will be able to also look up the colors key if you need to.
colors[colors_key['blue']][0] will return 'blue'
Something like that.
And then, while you're at it, you can make a dict with the number values as keys so that you can always use them to look up your colors, you know, if you need.
values = {5: [1, 'blue'], 6: [2, 'red'], 8: [3, 'yellow']}
Then, (colors[colors_key[values[5][1]]][0]) will return 'blue'.
Or you could use a list of lists.
Good luck!

actually I found a novel solution that really helped me out, If you are especially concerned with the index of a certain value in a list or data set, you can just set the value of dictionary to that Index!:
Just watch:
list = ['a', 'b', 'c']
dictionary = {}
counter = 0
for i in list:
dictionary[i] = counter
counter += 1
print(dictionary) # dictionary = {'a':0, 'b':1, 'c':2}
Now through the power of hashmaps you can pull the index your entries in constant time (aka a whole lot faster)

Consider why you are indexing
First, I would say to make sure you really need to index into the dict. A dict was originally intended not to even have an order, so perhaps there is alternate way to resolve the need to index that uses the strengths of the existing base Python data types.
For example, if you have a list of colors that are needed in a certain order, just store the list of colors, then index into those, and feed them into the dict to get the values.
color_order = [ 'blue', 'yellow', 'yellow', 'blue' ]
value_0 = colors[color_order[0]]
On the other hand, if you need some default color value as index 0, consider using a separate value to store the default, or add an additional entry that sets the default value that you can just key into instead of having to index:
default_color = 'blue'
default_value = colors[default_color]
colors = { 'default': '5', 'blue': '5', 'red': '6', 'yellow': '8' }
default_value = colors['default']
Find the index with a function
You can find a dict index by counting into the dict.keys() with a loop. If you use the enumerate() function, it will generate the index values automatically.
This is the most straight-forward, but costs a little more CPU every time you look up the index. This assumes an ordered dict (Python 3.7+ guarantees this).
To find the key at a given index:
def key_at_index(mydict, index_to_find):
for index, key in enumerate(mydict.keys()):
if index == index_to_find:
return key
return None # the index doesn't exist
To find the index of an key:
def index_of_key(mydict, key_to_find):
for index, key in enumerate(mydict.keys()):
if key == key_to_find:
return index
return None # the key doesn't exist
Create a list of keys
If you need a solution that will be accessed a lot, you can create a duplicate list of the keys that mirrors the keys in your current dictionary, then index into the list if you know the index, or use the list.index(item) method of the list to find the index. A list is preferable to creating a dict with the indexes, because a list inherently already has indexes, and built-in functions are typically much faster and more likely to correctly handle edge and corner cases.
There is extra overhead with this method, but it could be worth it if you are doing a lot of data analysis and need to access the indexes regularly.
# Note: you don't actually need the `.keys()`, but it's easier to understand
colors_i = list(colors.keys())
index_blue = colors.index('blue')
index0 = colors_i[0]
value0 = colors[index0]
print(f'colors: {colors}\ncolor_i: {colors_i}')
print(f'index_blue = {index_blue}, index0 = "{index0}", value0 = "{value0}"')
# colors: {'blue': '5', 'red': '6', 'yellow': '8'}
# color_i: ['blue', 'red', 'yellow']
# index_blue = 0, index0 = "blue", value0 = "5"
Note: This is static, and will not be updated if your source dictionary get's updated. You will need to add new items to both the list and the dict to keep them in sync
Function to update the dict and list
The below is a function that will update your dict and index list at the same time. If an item already exists, it will update the value and not add it to the list (otherwise there will be a duplicate entry in the list, while the dict will only update the existing entry).
This approach could be extended into a class if doing large amounts of processing, especially if other extended functions are required on top of this.
def index_add_item(mydict, index_list, key, value):
# Note: The dict and list are passed by reference, so we can just update them
try: # in case key doesn't exist
existing_value = colors[key]
except KeyError: # key does not exist, update dict and list
mydict.update({key: value})
index_list.append(key)
else: # key already exists, just update value
mydict[key] = value
index_add_item(colors, colors_i, 'purple', '99')
print(f'colors: {colors}\ncolors_i: {colors_i}')
# colors: {'blue': '5', 'red': '6', 'yellow': '8', 'purple': '99'}
# colors_i: ['blue', 'red', 'yellow', 'purple']
index_add_item(colors, colors_i, 'blue', '1')
print(f'colors: {colors}\ncolors_i: {colors_i}')
# colors: {'blue': '1', 'red': '6', 'yellow': '8', 'purple': '99'}
# colors_i: ['blue', 'red', 'yellow', 'purple']

You can't, since dict is unordered. you can use .popitem() to get an arbitrary item, but that will remove it from the dict.

I moved further with LightCC answer:
def key_value(mydict, find_code, find_key, return_value):
for key in mydict:
if key[find_code] == find_key:
return key[return_value]
return None
and I am not sure if this def could be optimized further (as nearly as oneliner).

Given a dict mydict in Python 3.7 and later, after dict became ordered by order of insertion, one can do:
next(iter(mydict.items())) to retrieve the first key, value pair that was inserted.
next(iter(mydict.keys())) to retrieve the first key that was inserted.
next(iter(mydict.value())) to retrieve the first value that was inserted.
This approach does not require iterating through all the elements of the dictionary.

Simple code that works.
# Example dictionary
d = {
'a': 5,
'b': 6,
'c': 7,
'd': 8,
'e': 9,
}
# Index you want
index = 3
# Use the fact that d.keys() is ordered the same as d.values()
value = d[list(d.keys())[index]]
print(value)
Will print
8
Keys and values are ordered the same according to this question

Related

How to Update values (List forms) from while loop in dictionary python

I don't really understand the concept of python dictionary, can anyone help me? I want the program to have similar functionality as append in list python
d = {'key': ['value']}
print(d)
# {'key': ['value']}
d['key'] = ['mynewvalue']
print(d)
# {'key': ['mynewvalue']}
what I want the output of the program, either :
print(d)
#{'key': ['value'],'key': ['mynewvalue']}
or :
print(d)
#{'key': ['value','mynewvalue']}
Sure: first thing first, you can't have two identical keys in a dictionary. So:
{'key': 'myfirstvalue', 'key': 'mysecondvalue'}
wouldn't work. If a key has multiple values, then the key's value should be a list of values, like in your last option. Like in a real dictionary, you won't find, word: definition, word: another definition but word: a list of definitions.
In this regard, you could kind of think of a dictionary as a collection of variables - you can't assign two values to a variable except by assigning a list of values to variable.
x = 4
x = 5
is working code, but the first line is rendered meaningless. x is only equal to 5, not both 4 and 5. You could, however, say:
x = [4, 5]
I often use dictionaries for trees of data. For example, I'm working on a project involving counties for every state in the US. I have a dictionary with a key for each state, and the value of each key is another dictionary, with a key for each county, and the value for each of those dictionaries is another dictionary with the various data points for that county.
That said, you can interact with your dictionary just like you would with variables.
mylist = [1, 2, 3, 4]
mylist.append(5)
print(mylist)
will print:
[1,2,3,4,5]
But also:
mydict = {'mylist': [1,2,3,4]}
mydict['mylist'].append(5)
does the same thing.
mydict['mylist']
is the same as
mylist
in the first example. Both are equal to the list [1,2,3,4]
You cannot have same keys multiple times in a dict in python. The first output scenario you gave is invalid. The value of a dict can contain any data and in your case, it can be accessed and modified just as a list. You can modify the code as given below to get the output as desired in scenario number 2.
d = {'key': ['value']}
print(d)
# {'key': ['value']}
d['key'].append('mynewvalue')
print(d)
#{'key': ['value','mynewvalue']}
you can try it:
d = {'key': ['value']}
d['key'].append("mynewvalue")
print(d)
Output will be: {'key': ['value', 'mynewvalue']}
For the first implementation you want, I think you are violating the entire idea of dictionary, we can not have multiple keys with the same name.
For the second implementation you could write a function like this:
def updateDict(mydict,value):
mydict['key'].append(value)

Compare value in dict with other values

I'd like to compare all entries in a dict with all other entries – if the values are within a close enough range, I want to merge them under a single key and delete the other key. But I cannot figure out how to iterate through the dict without errors.
An example version of my code (not the real set of values, but you get the idea):
things = { 'a': 1, 'b': 3, 'c': 22 }
for me in things.iteritems():
for other in things.iteritems():
if me == other:
continue
if abs(me-other) < 5:
print 'merge!', me, other
# merge the two into 'a'
# delete 'b'
I'd hope to then get:
>> { 'a': [ 1, 2 ], 'c': 22 }
But if I run this code, I get the first two that I want to merge:
>> merge! ('a', 1) ('b', 2)
Then the same one in reverse (which I want to have merged already):
>> duplicate! ('b', 2) ('a', 1)
If I use del things['b'] I get an error that I'm trying to modify the dict while iterating. I see lots of "how to remove items from a dict" questions, and lots about comparing two separate dicts, but not this particular problem (as far as I can tell).
EDIT
Per feedback in the comments, I realized my example is a little misleading. I want to merge two items if their values are similar enough.
So, to do this in linear time (but requiring extra space) use an intermediate dict to group the keys by value:
>>> things = { 'fruit': 'tomato', 'vegetable': 'tomato', 'grain': 'wheat' }
>>> from collections import defaultdict
>>> grouper = defaultdict(list)
>>> for k, v in things.iteritems():
... grouper[v].append(k)
...
>>> grouper
defaultdict(<type 'list'>, {'tomato': ['vegetable', 'fruit'], 'wheat': ['grain']})
Then, you simply take the first item from your list of values (that used to be keys), as the new key:
>>> {v[0]:k for k, v in grouper.iteritems()}
{'vegetable': 'tomato', 'grain': 'wheat'}
Note, dictionaries are inherently unordered, so if order is important, you should have been using an OrderedDict from the beginning.
Note that your result will depend on the direction of the traversal. Since you are bucketing data depending on distance (in the metric sense), either the right neighbor or the left neighbor can claim the data point.

Adding the values in a two different dictionaries and creating a new dictionary

I have the following two dictionaries
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
and
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
I need to collate and sum the scores for keys a and b in both dictionaries to produce the following output:
The answer could be 'done' using one of the following two methods (and there may be others I'd be interested to hear)
1. Using the creation of a new dictionary:
finalscores={a:30,b:30} #adds up the scores for keys a and b and makes a new dictionary
OR
2. update the scores2 dictionary (and add the values from scores1 to the scores2 corresponding respective values
An accepted answer would show both the above with any suitable explanation as well as suggest any more astute or efficient ways of solving the problem.
There was a suggestion on another SO answer that the dictionaries could simply be added:
print(scores1+scores2)
Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?
But I want to do this in the simplest method possible, without iterator imports or classes
I have also tried, but to no avail:
newdict={}
newdict.update(scores1)
newdict.update(scores2)
for i in scores1.keys():
try:
addition = scores[i] + scores[i]
newdict[i] = addition
except KeyError:
continue
For the first solution:
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
finalscores=dict((key, sum([scores1[key] if key in scores1 else 0, scores2[key] if key in scores2 else 0])) for key in set(scores1.keys()+scores2.keys()))
print(finalscores)
# outputs {'a': 30, 'c': 30, 'b': 30, 'd': 10}
This iterates through a set of all keys in both dictionaries, creates a tuple with the values of the key in both dictionaries or 0 and then passes said tuple through the sum function adding the results. Finally, it generates a dictionary.
EDIT
In multiple lines, to understand the logic, this is what the one-liner does:
finalscores = {}
for key in set(scores1.keys()+scores2.keys()):
score_sum = 0
if key in scores1:
score_sum += scores1[key]
if key in scores2:
score_sum += scores2[key]
finalscores[key] = score_sum
For the second solution:
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
for k1 in scores1:
if k1 in scores2:
scores2[k1] += scores1[k1] # Adds scores1[k1] to scores2[k1], equivalent to do scores2[k1] = scores2[k1] + scores1[k1]
else:
scores2[k1] = scores1[k1]
print(scores2)
# outputs {'a': 30, 'c': 30, 'b': 30, 'd': 10}

Dividing dictionary into nested dictionaries, based on the key's name on Python 3.4

I have the following dictionary (short version, real data is much larger):
dict = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}
I want to divide it into smaller nested dictionaries, depending on a part of the key name.
Expected output would be:
# fixed closing brackets
dict1 = {'C-STD-B&M-SUM: {'-1': 0, '-10': 4.520475}}
dict2 = {'H-NSW-BAC-ART: {'-9': 0.33784000000000003, '0': 0}}
dict3 = {'H-NSW-BAC-ENG: {'-59': 0.020309999999999998, '-6': 0}}
Logic behind is:
dict1: if the part of the key name is 'C-STD-B&M-SUM', add to dict1.
dict2: if the part of the key name is 'H-NSW-BAC-ART', add to dict2.
dict3: if the part of the key name is 'H-NSW-BAC-ENG', add to dict3.
Partial code so far:
def divide_dictionaries(dict):
c_std_bem_sum = {}
for k, v in dict.items():
if k[0:13] == 'C-STD-B&M-SUM':
c_std_bem_sum = k[14:17], v
What I'm trying to do is to create the nested dictionaries that I need and then I'll create the dictionary and add the nested one to it, but I'm not sure if it's a good way to do it.
When I run the code above, the variable c_std_bem_sum becomes a tuple, with only two values that are changed at each iteration. How can I make it be a dictionary, so I can later create another dictionary, and use this one as the value for one of the keys?
One way to approach it would be to do something like
d = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}
def divide_dictionaries(somedict):
out = {}
for k,v in somedict.items():
head, tail = k.split(":")
subdict = out.setdefault(head, {})
subdict[tail] = v
return out
which gives
>>> dnew = divide_dictionaries(d)
>>> import pprint
>>> pprint.pprint(dnew)
{'C-STD-B&M-SUM': {'-1': 0, '-10': 4.520475},
'H-NSW-BAC-ART': {'-9': 0.33784000000000003, '0': 0},
'H-NSW-BAC-ENG': {'-59': 0.020309999999999998, '-6': 0}}
A few notes:
(1) We're using nested dictionaries instead of creating separate named dictionaries, which aren't convenient.
(2) We used setdefault, which is a handy way to say "give me the value in the dictionary, but if there isn't one, add this to the dictionary and return it instead.". Saves an if.
(3) We can use .split(":") instead of hardcoding the width, which isn't very robust -- at least assuming that's the delimiter, anyway!
(4) It's a bad idea to use dict, the name of a builtin type, as a variable name.
That's because you're setting your dictionary and overriding it with a tuple:
>>> a = 1, 2
>>> print a
>>> (1,2)
Now for your example:
>>> def divide_dictionaries(dict):
>>> c_std_bem_sum = {}
>>> for k, v in dict.items():
>>> if k[0:13] == 'C-STD-B&M-SUM':
>>> new_key = k[14:17] # sure you don't want [14:], open ended?
>>> c_std_bem_sum[new_key] = v
Basically, this grabs the rest of the key (or 3 characters, as you have it, the [14:None] or [14:] would get the rest of the string) and then uses that as the new key for the dict.

retrieving keys from dictionaries depending on value in python

I'm trying to find the most efficient way in python to create a dictionary of 'guids' (point ids in rhino) and retrieve them depending on the value(s) I assign them, change that value(s) and restoring them back in the dictionary. One catch is that with Rhinoceros3d program the points have a random generated ID number which I don't know so I can only call them depending on the value I give them.
are dictionaries the correct way? should the guids be the value instead of the keys?
a very basic example :
arrPts=[]
arrPts = rs.GetPoints() # ---> creates a list of point-ids
ptsDict = {}
for ind, pt in enumerate(arrPts):
ptsDict[pt] = ('A'+str(ind))
for i in ptsDict.values():
if '1' in i :
print ptsDict.keys()
how can I make the above code print the key that has the value '1' , instead of all the keys? and then change the key's value from 1 to e.g. 2 ?
any help also on the general question would be appreciated to know I'm in the right direction.
Thanks
Pav
You can use dict.items().
An example:
In [1]: dic={'a':1,'b':5,'c':1,'d':3,'e':1}
In [2]: for x,y in dic.items():
...: if y==1:
...: print x
...: dic[x]=2
...:
a
c
e
In [3]: dic
Out[3]: {'a': 2, 'b': 5, 'c': 2, 'd': 3, 'e': 2}
dict.items() returns a list of tuples containing keys and value pairs in python 2.x:
In [4]: dic.items()
Out[4]: [('a', 2), ('c', 2), ('b', 5), ('e', 2), ('d', 3)]
and in python 3.x it returns an iterable view instead of list.
I think you want the GUID's to be values, not keys, since it looks like you want to look them up by something you assign. ...but it really depends on your use case.
# list of GUID's / Rhinoceros3d point ids
arrPts = ['D20EA4E1-3957-11d2-A40B-0C5020524153',
'1D2680C9-0E2A-469d-B787-065558BC7D43',
'ED7BA470-8E54-465E-825C-99712043E01C']
# reference each of these by a unique key
ptsDict = dict((i, value) for i, value in enumerate(arrPts))
# now `ptsDict` looks like: {0:'D20EA4E1-3957-11d2-A40B-0C5020524153', ...}
print(ptsDict[1]) # easy to "find" the one you want to print
# basically make both keys: `2`, and `1` point to the same guid
# Note: we've just "lost" the previous guid that the `2` key was pointing to
ptsDict[2] = ptsDict[1]
Edit:
If you were to use a tuple as the key to your dict, it would look something like:
ptsDict = {(loc, dist, attr3, attr4): 'D20EA4E1-3957-11d2-A40B-0C5020524153',
(loc2, dist2, attr3, attr4): '1D2680C9-0E2A-469d-B787-065558BC7D43',
...
}
As you know, tuples are immutable, so you can't change the key to your dict, but you can remove one key and insert another:
oldval = ptsDict.pop((loc2, dist2, attr3, attr4)) # remove old key and get value
ptsDict[(locx, disty, attr3, attr4)] = oldval # insert it back in with a new key
In order to have one key point to multiple values, you'd have to use a list or set to contain the guids:
{(loc, dist, attr3, attr4): ['D20E...', '1D2680...']}

Categories

Resources