Iterating JSON structure of list object and finding next keys - python

I have a Json list and I want to print all the keys from a given key till the end of dictionary. But the code I wrote is very complex. How to do it with less complexity ?
I'm using Python 3
dictionary = [{"a": "1"}, {"b": "2"}, {"c": "3"}, {"d": "4"}]
try:
for token in dictionary:
if "b" in list(token.keys())[0]:
new_dict = dictionary[len(list(token.keys())[0]):]
for i in new_dict:
print(new_dict[len(list(i.keys())[0]):])
break
else:
print("Inception")
except Exception as error:
print(str(error))
DESIRED
Input: b
Output: c, d
My Output:
Inception
[{'c': '3'}, {'d': '4'}]
[{'c': '3'}, {'d': '4'}]
[{'c': '3'}, {'d': '4'}]

Use itertools.dropwhile() to skip all dictionaries that don't have a 'b' key:
from itertools import dropwhile
filtered = dropwhile(lambda t: 'b' not in t, dictionary)
next(filtered) # skip the dictionary with `b` in it.
for token in filtered:
print(token)
This prints all dictionaries after the first. If you only need to print their keys, do so explicitly:
filtered = dropwhile(lambda t: 'b' not in t, dictionary)
next(filtered) # skip the dictionary with `b` in it.
for token in filtered:
print(*token, sep='\n')
This prints the keys on separate lines; if there is just one key, then that's all that'll be printed for each token dictionary.)
As a side note: you really do not want to use list(dict.keys())[0]. Before Python 3.6, dictionaries have no set order (instead being subject to insertion and deletion history and the current random hash seed), so if you have more than one key what value you'll get is a gamble. And all you want to do is see if a key is present, so use a key in dictobject membership test.
To get the first key out of each dictionary, I'd use next(iter(dictobject)), avoiding creating a list:
first_key = next(iter(dictobject))
I'd only use this if I had single-key dictionaries. I'd also avoid using dictionaries for such a scenario; perhaps you really wanted to use an ordered dictionary instead (in Python < 3.6, use collections.OrderedDict(), otherwise use the regular dict type).

This is one way. The idea is to find the index of the dictionary with desired key. Then filter your list accordingly.
keys = [next(iter(x)) for x in dictionary]
res = keys[keys.index('b')+1:]
# ['c', 'd']

You can re-write your code as follows for your desired result.
found = False
for data in dictionary:
if found:
print(list(data.keys())[0])
if 'b' in data.keys():
found = True

Related

Swapping dictionary keys and values works only on 3 key-value pair dictionary

Here's a function that is supposed to swap dictionary keys and values. {'a': 3} is supposed to become {3: 'a'}.
def change_keys_values(d):
for key in d:
value = d[key]
del d[key]
d[value] = key
return d
I've realized that this function shouldn't work because I'm changing dictionary keys during iteration. This is the error I get: "dictionary keys changed during iteration". However, I don't get this error on a three key-value pair dictionary. So, while {'a': 3, 't': 8, 'r': 2, 'z': 44, 'u': 1, 'b': 4} results in the above mentioned error, {'a': 3, 't': 8, 'r': 2} gets solved without any issues. I'm using python 3. What is causing this?
You must never modify a dictionary inside a loop. The reason is the way the dictionaries are often implemented.
Hash Tables
Basically, when you create a dictionary, each item is indexed using the hash value of the key.
Dictionaries are implemented sparsely
Another implementation detail involves the fact that dictionaries are implemented in a sparse manner. Namely, when you create a dictionary, there are empty places in memory (called buckets). When you add or remove elements from a dictionary, it may hit a threshold where the dictionary key hashes are re-evaluated and as a consequence, the indexes are changed.
Roughly speaking, these two points are the reason behind the problem you are observing.
Moral Point: Never modify a dictionary inside a loop of any kind.
Here's a simple code to do what you want:
def change_keys_values(d):
new_dict = {value: key for key, value in d.items()}
return new_dict
You need to verify that the values are unique, after that, no problem :)
But be sure not to change a dictionary while parsing it. Otherwise, you could encounter an already changed index that get's interpreted twice or even more. I suggest making a new variable (a copy):
def invert(dict_: dict) -> dict:
if list(set(dict_.values())) == list(dict_.values()): # evaluates if "inverting key:value" is possible (if keys are unique)
return {b: a for a, b in dict_.items()}
else:
raise ValueError("Dictionary values contain duplicates. Inversion not possible!")
print(invert({"a": 1, "b": 2, "c": 3, "d": 4})) # works
print(invert({"a": 1, "b": 2, "c": 3, "d": 3})) # fails
To fix your issue, just iterate over copy, not the original dict:
import copy
def change_keys_values(d):
for key in copy.deepcopy(d):
value = d[key]
del d[key]
d[value] = key
return d
Then the good alternative using zip would be:
def change_keys_values(d):
a, b = zip(*d.items())
d = dict(list(zip(b,a)))
return d

Typeerror 'dict_keys' object is not subscriptable [duplicate]

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)
You can't, since dict is unordered. you can use .popitem() to get an arbitrary item, but that will remove it from the dict.
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']
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

How values and keys get assigned in a dictionary using python

I was running this code through python tutor, and was just confused as to how the keys and values get switched around. I also was confused as to what value myDict[d[key]] would correspond to as I'm not sure what the d in [d[key]] actually does.
def dict_invert(d):
'''
d: dict
Returns an inverted dictionary according to the instructions above
'''
myDict = {}
for key in d.keys():
if d[key] in myDict:
myDict[d[key]].append(key)
else:
myDict[d[key]] = [key]
for val in myDict.values():
val.sort()
return myDict
print(dict_invert({8: 6, 2: 6, 4: 6, 6: 6}))
In your function d is the dictionary being passed in. Your code is creating a new dictionary, mapping the other direction (from the original dictionary's values to its keys). Since there may not be a one to one mapping (since values can be repeated in a dictionary), the new mapping actually goes from value to a list of keys.
When the code loops over the keys in d, it then uses d[key] to look up the corresponding value. As I commented above, this is not really the most efficient way to go about this. Instead of getting the key first and indexing to get the value, you can instead iterate over the items() of the dictionary and get key, value 2-tuples in the loop.
Here's how I'd rewrite the function, in what I think is a more clear fashion (as well as perhaps a little bit more efficient):
def dict_invert(d):
myDict = {}
for key, value in d.items(): # Get both key and value in the iteration.
if value in myDict: # That change makes these later lines more clear,
myDict[value].append(key) # as they can use value instead of d[key].
else:
myDict[value] = [key] # here too
for val in myDict.values():
val.sort()
return myDict
The function you are showing inverts a dictionary d. A dictionary is a collection of unique keys that map to values which are not necessarily unique. That means that when you swap keys and values, you may get multiple keys that have the same value. Your function handles this by adding keys in the input to a list in the inverse, instead of storing them directly as values. This avoids any possibility of conflict.
Let's look at a sample conceptually first before digging in. Let's say you have
d = {
'a': 1,
'b': 1,
'c': 2
}
When you invert that, you will have the keys 1 and 2. Key 1 will have two values: 'a' and 'b'. Key 2 will only have one value: 'c'. I used different types for the keys and values so you can tell immediately when you're looking at the input vs the output. The output should look like this:
myDict = {
1: ['a', 'b'],
2: ['c']
}
Now let's look at the code. First you initialize an empty output:
myDict = {}
Then you step through every key in the input d. Remember that these keys will become the values of the output:
for key in d.keys():
The value in d for key is d[key]. You need to check if that's a key in myDict since values become keys in the inverse:
if d[key] in myDict:
If the input's value is already a key in myDict, then it maps to a list of keys from d, and you need to append another one to the list. Specifically, d[key] represents the value in d for the key key. This value becomes a key in myDict, which is why it's being indexed like that:
myDict[d[key]].append(key)
Otherwise, create a new list with the single inverse recorded in it:
else:
myDict[d[key]] = [key]
The final step is to sort the values of the inverse. This is not necessarily a good idea. The values were keys in the input, so they are guaranteed to be hashable, but not necessarily comparable to each other:
for val in myDict.values():
val.sort()
The following should raise an error in Python 3:
dict_invert({(1, 2): 'a', 3: 'b'})
myDict[d[key]] takes value of d[key] and uses it as a key in myDict, for example
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 1, 'beta': 2}
D[d['a']] = 3
D[d['b']] = 4
now when contents of d and D should be as following
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 3, 'beta': 4}
d is the dictionary you are passing into the function
def dict_invert(d)
When you create
myDict[d[key]] = d
Its meaning is
myDict[value of d] = key of d
Resulting in
myDict = {'value of d': 'key of d'}

Converting dictionary into string

d={'a':'Apple','b':'ball','c':'cat'}
The above dictionary I have and I want my Output like the below-mentioned result
res="a=Apple,b=ball,c=cat"
Is it possible in a pythonic way then please answer it I have tried various method but did not get desired output?
Read your dictionary as key/value pairs (dict.items()) and then just format them in a string you like:
d = {'a': 'Apple', 'b': 'ball', 'c': 'cat'}
res = ",".join("{}={}".format(*i) for i in d.items()) # a=Apple,c=cat,b=ball
The order, tho, cannot be guaranteed for a dict, use collections.OrderedDict() if order is important.
One way is to iterate via dict.items and use multiple str.join calls.
d = {'a':'Apple','b':'ball','c':'cat'}
res = ','.join(['='.join(i) for i in d.items()])
# 'a=Apple,b=ball,c=cat'
If you need items ordered by key, use sorted(d.items()).
def format_dict(d):
vals = list(d.values())
return "={},".join(d.keys()).format(*vals) + "={}".format(vals[-1])
d = {'a': 'Apple', 'b': 'ball', 'c': 'cat'}
format_dict(d) # -> 'a=Apple,b=ball,c=cat'
This joins all the keys into a large string containing replacement fields that we then format passing the dict values as args. There wasn't a trailing replacement field so we concatenate the last value in the dictionary to our large string.
For anyone coming here looking for a way to explicitly extract the dictionary keys and values (e.g. if further formatting is required):
d = {'a':'Apple','b':'ball','c':'cat'}
res = ','.join(f'{k}={v}' for k, v in d.items())
# --> a=Apple, b=ball, c=cat
(uses python 3.6+ f-strings)

Nested Dictionary check key value

I have a nested dictionary as shown below: (more than 2 keys "lots of lala's")
d={'lala': {'temp1': 'c', 'comp_b': 'bc', 'temp': 'b', 'comp_a': 'ac'}, 'lala1': {'temp1': 'c1', 'comp_b': 'bc1', 'temp': 'b1', 'comp_a': ''}
For all the parent keys in "a", I need to check if keys(comp_a and comp_b) have valid values.
In this case, "comp_a" of "lala1" doesn't have a value. So I need my function to only return "lala" as the output.
Parent keys to check=> a= ['lala','lala1']
Required values for keys=> compulsory= ['comp_b','comp_a']
Here's what I have so far:
def check_args(a,d):
compulsory=['comp_b','comp_a']
valid=[]
for a in d:
for elements in compulsory:
try:
if d.get(a,{}).get(elements) !='':
print "Valid"
except:
break
else:
print "Can't parse details of " + a + " as mandatory data missing "
continue
Question:
How do I return the valid parent keys i.e. "lala"?
Is there a better way to do what I've done so far?
Here is a clean way without try except
d={'lala': {'temp1': 'c', 'comp_b': 'bc', 'temp': 'b', 'comp_a': 'ac'}, 'lala1': {'temp1': 'c1', 'comp_b': 'bc1', 'temp': 'b1', 'comp_a': ''}}
compulsory= ['comp_b','comp_a']
ok_keys = [k for k,v in d.iteritems() if all([c in v and v[c]!='' for c in compulsory])]
ok_keys #<-- prints ['lala']
The logic all takes place in the list comprehension which first loops through the keys in d, and tests that all of the compulsory keys are within d[k] and that the d[k][c] values are not empty.
If I understood the question correctly you want to check for the dictionary values whether these have, for all compulsory elements a value?
There most certainly is a more elegant way to do this: you can use list comprehension:
e = {}
[key for key in a if all(d.get(key,e).get(c) for c in compulsory)]
The all(d.get(key,e).get(c) for c in compulsory) is crucial here since it is a filter condition. The all(..) will thus start enumerating over the compulsory list and for each element c, it will fetch that element and see if its truthiness is True. The empty string has a truthiness of False, so that won't work. If the key is not in the dictionary, then .get(c) will return None which has a truthiness of False as well.

Categories