Compare value in dict with other values - python

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.

Related

How can i take a given dict and return a new one with multiple values for one key? [duplicate]

This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 2 years ago.
I'm new to python and struggling with this question - Create a function which works as follows:
d={1:"x",2:"y",3:"x",4:"z"}
invert_d(d)
{"x":(1,3),"y":(2),"z":(4)}
So invert_d gives a new dict with the values of multiple keys as lists.
I have to say, that I never worked with dicts and started python 1 week ago...so I'm a total newb.
I am new to python.... and I'm struggling with this question:
Edit: I read wrong and fixed the Dict. Sorry guys :(
Also we cant import in the exam
You can use the setdefault method to make the dictionary construction simpler. A very basic way to do it is like this:
d={1:"x",2:"y",3:"x",4:"z"}
def invertDict(d):
result = dict()
for k,v in d.items(): result.setdefault(v,[]).append(k)
return result
print(invertDict(d))
{'x': [1, 3], 'y': [2], 'z': [4]}
If you want a one-liner solution, you can use a dictionary comprehension. Here's one that outputs the list of keys as tuples:
def invertDict(d):
return {v:tuple(inv[v]) for inv in [{}] for k,v in d.items() if [inv.setdefault(v,[]).append(k)] }
print(invertDict(d))
{'x': (1, 3), 'y': (2,), 'z': (4,)}
A dict associates exactly one value with a particular key, so your original dict d would see two different values for the key "x" (first 1 and then 3), and the last one would replace previous ones. If you have access to an interactive Python session, this looks like:
$ python
Python 3.9.1 (default, Dec 13 2020, 11:55:53)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {"x": 1, "y": 2, "x": 3, "z": 5}
>>> d
{'x': 3, 'y': 2, 'z': 5}
(The d by itself there just asks Python to use print to display the current value, as if you had called print(d).)
So at this point you have some options. You could just define a dict to contain the eventual values you want: {"x":(1,3),"y":(2,),"z":(5,)}. Or, if you actually have a source of a stream or list of pairs of values that you want to process into a dict using a function like the one you describe, we can do that, too, but we need to use something like a list of tuples as the input, rather than a dict: l = [("x", 1), ("y", 2), ("x", 3), ("z", 5)]. With that new notion of the input, we could write a function that in some way processes each element of that list and compiles those elements into a particular dict. Here's one way that could look (without any error handling):
from functools import reduce
def add_tuple_to_dict(d, t): # here `d` is the dict and `t` is the tuple
if t[0] in d:
d[t[0]].append(t[1])
else:
d[t[0]] = [t[1],]
return d
def invert_d(list_of_tuples):
return reduce(add_tuple_to_dict, list_of_tuples, {})
Edit: after submitting the above, I now realize you do actually want to invert your dict, which could look like this, instead:
from functools import reduce
def add_tuple_to_dict(d, t): # here `d` is the dict and `t` is the tuple
if t[1] in d:
d[t[1]].append(t[0])
else:
d[t[1]] = [t[0],]
return d
def invert_d(d):
return reduce(add_tuple_to_dict, d.items(), {})
You can use collections.defaultdict to initially create your dictionary having keys with lists as values. Then convert it to a dict having keys with tuples as values:
import collections
d = {1: "x", 2: "y", 3: "x", 4: "z"}
def invert(d):
# first as a dict with lists as values
inv = collections.defaultdict(list)
for k, v in d.items():
# note that the previous VALUE is the key of the inverted dict
inv[v].append(k)
# then convert the existing "list of values" to "tuples of values"
inv = {k: tuple(v) for k, v in inv.items()}
return inv
invert(d)
# {'x': (1, 3), 'y': (2,), 'z': (4,)}
What defaultdict does is when a value in the dict is looked up (get or set), if it doesn't exist, it automatically creates a value with the default factory provided. In this case, list.
So each value when looked up is set to an empty list. In the loop, the new values (keys of the old one), are appended to this list. If it didn't exist before, the new value is appended to the empty list. If it did exist (from a previous iteration) and has a value, then a new value is appended to that list.
Since what you want at the end is tuples of values and not lists, I have a dictionary comprehension which uses the same keys and converts the values to tuples.
You can do a reverse look-up
invert_d = lambda d: { v:[k for k in d if d[k] == v] for v in d.values() }
whereat you can read v as value and k as key.
d={1:"x",2:"y",3:"x",4:"z"}
invert_d(d)
{'x': [1, 3], 'y': [2], 'z': [4]}
Edit
Maybe a brief explanation: This is a Lambda Expressions using two List Comprehensions. One as value and an outer one to wrap it up (actually a dictionary comprehensions but works the same).
This is not really performant but totally sufficient for every day usage.

Dictionaries pointing to another dictionary in Python

Let's say I have a dictionary dic = {k: v}. My goal is to create another data structure that will point to a subset of a dictionary, accessed under a single key.
E.g: dic = {1: 'a', 2: 'b', 3: 'c', 4: 'f'}.
I would like a pointer only to keys 1 and 3, for instance, but retrievable under a single key 'k1', and to keys 2 and 4 retrievable under a single key 'k2' without the need to do a hardcopy. My data won't change throughout the application.
I know I can create another dictionary subdic = {'k1': (a, c), 'k2': (b, f)}, but that would require extra memory, right?
How can I do that only with some sort of pointers? With a softcopy, such that values are only once in memory from the original dictionary dic.
You can create a second dictionary like this
dic2 = {'k1': (dic[1], dic[3])}
Doing so, you don't actually use extra memory (only marginally) because the objects in the tuple are the same as the ones in your original dic (they occupy the same space in memory). You can check that it is true by doing:
id(dic2['k1'][0]) == id(dic[1]) # True

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...']}

python dict: get vs setdefault

The following two expressions seem equivalent to me. Which one is preferable?
data = [('a', 1), ('b', 1), ('b', 2)]
d1 = {}
d2 = {}
for key, val in data:
# variant 1)
d1[key] = d1.get(key, []) + [val]
# variant 2)
d2.setdefault(key, []).append(val)
The results are the same but which version is better or rather more pythonic?
Personally I find version 2 harder to understand, as to me setdefault is very tricky to grasp. If I understand correctly, it looks for the value of "key" in the dictionary, if not available, enters "[]" into the dict, returns a reference to either the value or "[]" and appends "val" to that reference. While certainly smooth it is not intuitive in the least (at least to me).
To my mind, version 1 is easier to understand (if available, get the value for "key", if not, get "[]", then join with a list made up from [val] and place the result in "key"). But while more intuitive to understand, I fear this version is less performant, with all this list creating. Another disadvantage is that "d1" occurs twice in the expression which is rather error-prone. Probably there is a better implementation using get, but presently it eludes me.
My guess is that version 2, although more difficult to grasp for the inexperienced, is faster and therefore preferable. Opinions?
Your two examples do the same thing, but that doesn't mean get and setdefault do.
The difference between the two is basically manually setting d[key] to point to the list every time, versus setdefault automatically setting d[key] to the list only when it's unset.
Making the two methods as similar as possible, I ran
from timeit import timeit
print timeit("c = d.get(0, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000)
print timeit("c = d.get(1, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000)
print timeit("d.setdefault(0, []).extend([1])", "d = {1: []}", number = 1000000)
print timeit("d.setdefault(1, []).extend([1])", "d = {1: []}", number = 1000000)
and got
0.794723378711
0.811882272256
0.724429205999
0.722129751973
So setdefault is around 10% faster than get for this purpose.
The get method allows you to do less than you can with setdefault. You can use it to avoid getting a KeyError when the key doesn't exist (if that's something that's going to happen frequently) even if you don't want to set the key.
See Use cases for the 'setdefault' dict method and dict.get() method returns a pointer for some more info about the two methods.
The thread about setdefault concludes that most of the time, you want to use a defaultdict. The thread about get concludes that it is slow, and often you're better off (speed wise) doing a double lookup, using a defaultdict, or handling the error (depending on the size of the dictionary and your use case).
The accepted answer from agf isn't comparing like with like. After:
print timeit("d[0] = d.get(0, []) + [1]", "d = {1: []}", number = 10000)
d[0] contains a list with 10,000 items whereas after:
print timeit("d.setdefault(0, []) + [1]", "d = {1: []}", number = 10000)
d[0] is simply []. i.e. the d.setdefault version never modifies the list stored in d. The code should actually be:
print timeit("d.setdefault(0, []).append(1)", "d = {1: []}", number = 10000)
and in fact is faster than the faulty setdefault example.
The difference here really is because of when you append using concatenation the whole list is copied every time (and once you have 10,000 elements that is beginning to become measurable. Using append the list updates are amortised O(1), i.e. effectively constant time.
Finally, there are two other options not considered in the original question: defaultdict or simply testing the dictionary to see whether it already contains the key.
So, assuming d3, d4 = defaultdict(list), {}
# variant 1 (0.39)
d1[key] = d1.get(key, []) + [val]
# variant 2 (0.003)
d2.setdefault(key, []).append(val)
# variant 3 (0.0017)
d3[key].append(val)
# variant 4 (0.002)
if key in d4:
d4[key].append(val)
else:
d4[key] = [val]
variant 1 is by far the slowest because it copies the list every time, variant 2 is the second slowest, variant 3 is the fastest but won't work if you need Python older than 2.5, and variant 4 is just slightly slower than variant 3.
I would say use variant 3 if you can, with variant 4 as an option for those occasional places where defaultdict isn't an exact fit. Avoid both of your original variants.
For those who are still struggling in understanding these two term, let me tell you basic difference between get() and setdefault() method -
Scenario-1
root = {}
root.setdefault('A', [])
print(root)
Scenario-2
root = {}
root.get('A', [])
print(root)
In Scenario-1 output will be {'A': []} while in Scenario-2 {}
So setdefault() sets absent keys in the dict while get() only provides you default value but it does not modify the dictionary.
Now let come where this will be useful-
Suppose you are searching an element in a dict whose value is a list and you want to modify that list if found otherwise create a new key with that list.
using setdefault()
def fn1(dic, key, lst):
dic.setdefault(key, []).extend(lst)
using get()
def fn2(dic, key, lst):
dic[key] = dic.get(key, []) + (lst) #Explicit assigning happening here
Now lets examine timings -
dic = {}
%%timeit -n 10000 -r 4
fn1(dic, 'A', [1,2,3])
Took 288 ns
dic = {}
%%timeit -n 10000 -r 4
fn2(dic, 'A', [1,2,3])
Took 128 s
So there is a very large timing difference between these two approaches.
You might want to look at defaultdict in the collections module. The following is equivalent to your examples.
from collections import defaultdict
data = [('a', 1), ('b', 1), ('b', 2)]
d = defaultdict(list)
for k, v in data:
d[k].append(v)
There's more here.
1. Explained with a good example here:
http://code.activestate.com/recipes/66516-add-an-entry-to-a-dictionary-unless-the-entry-is-a/
dict.setdefault typical usage
somedict.setdefault(somekey,[]).append(somevalue)
dict.get typical usage
theIndex[word] = 1 + theIndex.get(word,0)
2. More explanation : http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
dict.setdefault() is equivalent to get or set & get. Or set if necessary then get. It's especially efficient if your dictionary key is expensive to compute or long to type.
The only problem with dict.setdefault() is that the default value is always evaluated, whether needed or not. That only matters if the default value is expensive to compute. In that case, use defaultdict.
3. Finally the official docs with difference highlighted http://docs.python.org/2/library/stdtypes.html
get(key[, default])
Return the value for key if key is in the dictionary, else default. If
default is not given, it defaults to None, so that this method never
raises a KeyError.
setdefault(key[, default])
If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.
The logic of dict.get is:
if key in a_dict:
value = a_dict[key]
else:
value = default_value
Take an example:
In [72]: a_dict = {'mapping':['dict', 'OrderedDict'], 'array':['list', 'tuple']}
In [73]: a_dict.get('string', ['str', 'bytes'])
Out[73]: ['str', 'bytes']
In [74]: a_dict.get('array', ['str', 'byets'])
Out[74]: ['list', 'tuple']
The mechamism of setdefault is:
levels = ['master', 'manager', 'salesman', 'accountant', 'assistant']
#group them by the leading letter
group_by_leading_letter = {}
# the logic expressed by obvious if condition
for level in levels:
leading_letter = level[0]
if leading_letter not in group_by_leading_letter:
group_by_leading_letter[leading_letter] = [level]
else:
group_by_leading_letter[leading_letter].append(word)
In [80]: group_by_leading_letter
Out[80]: {'a': ['accountant', 'assistant'], 'm': ['master', 'manager'], 's': ['salesman']}
The setdefault dict method is for precisely this purpose. The preceding for loop can be rewritten as:
In [87]: for level in levels:
...: leading = level[0]
...: group_by_leading_letter.setdefault(leading,[]).append(level)
Out[80]: {'a': ['accountant', 'assistant'], 'm': ['master', 'manager'], 's': ['salesman']}
It's very simple, means that either a non-null list append an element or a null list append an element.
The defaultdict, which makes this even easier. To create one, you pass a type or function for generating the default value for each slot in the dict:
from collections import defualtdict
group_by_leading_letter = defaultdict(list)
for level in levels:
group_by_leading_letter[level[0]].append(level)
There is no strict answer to this question. They both accomplish the same purpose. They can both be used to deal with missing values on keys. The only difference that I have found is that with setdefault(), the key that you invoke (if not previously in the dictionary) gets automatically inserted while it does not happen with get(). Here is an example:
Setdefault()
>>> myDict = {'A': 'GOD', 'B':'Is', 'C':'GOOD'} #(1)
>>> myDict.setdefault('C') #(2)
'GOOD'
>>> myDict.setdefault('C','GREAT') #(3)
'GOOD'
>>> myDict.setdefault('D','AWESOME') #(4)
'AWESOME'
>>> myDict #(5)
{'A': 'GOD', 'B': 'Is', 'C': 'GOOD', 'D': 'AWSOME'}
>>> myDict.setdefault('E')
>>>
Get()
>>> myDict = {'a': 1, 'b': 2, 'c': 3} #(1)
>>> myDict.get('a',0) #(2)
1
>>> myDict.get('d',0) #(3)
0
>>> myDict #(4)
{'a': 1, 'b': 2, 'c': 3}
Here is my conclusion: there is no specific answer to which one is best specifically when it comes to default values imputation. The only difference is that setdefault() automatically adds any new key with a default value in the dictionary while get() does not. For more information, please go here !
In [1]: person_dict = {}
In [2]: person_dict['liqi'] = 'LiQi'
In [3]: person_dict.setdefault('liqi', 'Liqi')
Out[3]: 'LiQi'
In [4]: person_dict.setdefault('Kim', 'kim')
Out[4]: 'kim'
In [5]: person_dict
Out[5]: {'Kim': 'kim', 'liqi': 'LiQi'}
In [8]: person_dict.get('Dim', '')
Out[8]: ''
In [5]: person_dict
Out[5]: {'Kim': 'kim', 'liqi': 'LiQi'}

How to index into a dictionary?

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

Categories

Resources