I'm trying to define a function that receive infinite values in dictonary, but the the exit is taking only the characters of the last 2 key and value.
Any suggestion?
def infinityInvent():
infinityInvent = []
while True:
keys = input(f'Enter a item (or blank to stop): ')
values = input(f'What the value? ')
if keys == '':
break
infinityInvent = dict(zip(keys, values)) # or infinityInvent = {k: v for k, v in zip(keys, values)}
infinityInvent()
You need to set an item in the dict, not redefine the dict:
def infinityInvent():
infinityInvent = {}
while True:
key = input(f'Enter a item (or blank to stop): ')
if key == '':
break
value = input(f'What the value? ')
infinityInvent[key] = value
return infinityInvent
print(infinityInvent())
Related
I'm trying to pull nested values from a json file. I want to print out each of the values for every "id" key. I think I'm close but can't figure out why the obj type changes from a dict to a list, and then why I'm unable to parse that list.
Here is a link to the json I'm working with: http://hastebin.com/ratevimixa.tex
and here is my current code:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import json
json_data = open('JubJubProductions.json', 'r+')
jdata = json.loads(json_data.read().decode("utf-8"))
def recursion(dict):
for key, value in dict.items():
if type(value) == type(dict):
if key != "paging":
for key, value in value.items():
if isinstance (value,list):
print key
# place where I need to enter list comprehension?
if type(value) == type(dict):
if key == "id":
print " id found " + value
if key != "id":
print key + " 1st level"
if key == "id":
print key
else:
if key == "id":
print "id found " + value
if __name__ == '__main__':
recursion(jdata)
-------------------------------------------------------------------------------------------update
This is now what I'm working with and it'll return a single id value, but not all of them:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import json
json_data = open('jubjubProductions', 'r+')
jdata = json.loads(json_data.read().decode("utf-8"))
def id_generator(d):
for k, v in d.items():
if k == "id":
yield v
elif isinstance(v, dict):
for id_val in id_generator(v):
yield id_val
if __name__ == '__main__':
for _ in id_generator(jdata):
print (_)
The JSON might contain a list of objects, which needs to be searched:
Python 2.7 version:
def item_generator(json_input, lookup_key):
if isinstance(json_input, dict):
for k, v in json_input.iteritems():
if k == lookup_key:
yield v
else:
for child_val in item_generator(v, lookup_key):
yield child_val
elif isinstance(json_input, list):
for item in json_input:
for item_val in item_generator(item, lookup_key):
yield item_val
Python 3.x version:
def item_generator(json_input, lookup_key):
if isinstance(json_input, dict):
for k, v in json_input.items():
if k == lookup_key:
yield v
else:
yield from item_generator(v, lookup_key)
elif isinstance(json_input, list):
for item in json_input:
yield from item_generator(item, lookup_key)
def id_generator(dict_var):
for k, v in dict_var.items():
if k == "id":
yield v
elif isinstance(v, dict):
for id_val in id_generator(v):
yield id_val
This will create an iterator which will yield every value on any level under key "id". Example usage (printing all of those values):
for _ in id_generator(some_json_dict):
print(_)
A little bit cleaner code (in python 3.x).
def parse_json_recursively(json_object, target_key):
if type(json_object) is dict and json_object:
for key in json_object:
if key == target_key:
print("{}: {}".format(target_key, json_object[key]))
parse_json_recursively(json_object[key], target_key)
elif type(json_object) is list and json_object:
for item in json_object:
parse_json_recursively(item, target_key)
json_object = {"key1": "val1", "key2": [{"key3":"val3", "key4": "val4"}, 123, "abc"]}
target_key = "key3"
parse_json_recursively(json_object, target_key) # Ouput key3: val3
Here is a simple recursive function to collect all values from a json document for a given key. Values can be json documents as well. The corresponding values appended to search_result.
def json_full_search(lookup_key, json_dict, search_result = []):
if type(json_dict) == dict:
for key, value in json_dict.items():
if key == lookup_key:
search_result.append(value)
json_full_search(lookup_key, value, search_result)
elif type(json_dict) == list:
for element in json_dict:
json_full_search(lookup_key, element, search_result)
return search_result
def get_val(j, s, v=None):
for k in j:
if v == None and k == s:
return j[k]
elif v != None and k == s and v == j[k]:
return True
elif v != None and k == s and v != j[k]:
return False
elif isinstance(j[k], dict):
return get_val(j[k], s, v)
You can use with for a json list l below,
for l in j:
r = get_val(l, 'key')
print(r)
for l in j:
r = get_val(l, 'mac', '00-60-2F-5A-04-51')
print(r)
Extension to python 3.x answer:
If nested json has similar keys under different list or dictionaries and you want to take first value of it..
below is the generic way:
def get_value_from_generator(json_input, lookup_key):
value = list(item_generator(json_input, lookup_key))
val = value[0] if value else None
print(f'lookup_key -> value : {val}')
return val
def item_generator(json_input, lookup_key):
if isinstance(json_input, dict):
for k, v in json_input.items():
print(f'{k} -- {v}')
if k == lookup_key:
yield v
else:
yield from item_generator(v, lookup_key)
elif isinstance(json_input, list):
for item in json_input:
yield from item_generator(item, lookup_key)
I've been searching for a solution for hours, but I can't find anything that helps. I'm having a problem converting a list of tuples into a dictionary. I get this error: 'ValueError: dictionary update sequence element #320 has length 1; 2 is required.' Here is a small example of the list of tuples:
[('Heat_equation', 262), ('Portal:Tertiary_Educatio', 262), ('Help:Wiki_markup_example', 262), ('Quantum_mechanics', 262), ('IB_Language_A:_English_Language_and_Literature_Course_Materia', 261), ('Pulmonary_Plethor', 261)]
This is what I want:
{'Heat_equation': 262, 'Portal:Tertiary_Educatio': 262, 'Help:Wiki_markup_example': 262, 'Quantum_mechanics': 262, 'IB_Language_A:_English_Language_and_Literature_Course_Materia': 261, 'Pulmonary_Plethor': 261}
The length is 2 though right? I'm not sure why I'm getting an error. Here is the function where I'm trying to convert the list of tuples into a dictionary:
import urllib.request
import json
import re
def get_url(url):
text = urllib.request.urlopen(url).read().decode()
return text
def get_choice():
try:
print("Select from the following options or press <?> to quit:")
print("1. Display top 1000 articles and views.")
print("2. Display top 100 learning projects.")
choice = input()
choice = int(choice)
if 1 <= choice <= 2:
print()
return choice
except ValueError:
if choice == "":
return None
print("%s is not a valid choice.\n" % choice)
def display_json(text):
lst = []
dictionary = json.loads(text)
for item in dictionary['items']:
for article in item['articles']:
line = (article['article'], article['views'])
lst.append(line)
return lst
def convert_dict(lst):
d = dict()
[d[t[0]].append(t[1]) if t[0] in (d.keys())
else d.update({t[0]: [t[1]]}) for t in lst]
dictionary = {k: v[0] for k, v in d.items()}
return dictionary
def display_dict(dictionary):
print(dictionary)
def learning_project(dictionary):
lst_2 = []
for key, value in dictionary.items():
string = str(key)
match = re.findall(r'([^\/ ]+).*?\w+.*', string)
match.append(value)
tup = tuple(match)
lst_2.append(tup)
return lst_2
def convert(lst_2):
p = dict(lst_2)
print(p)
def main():
while True:
url = "https://wikimedia.org/api/rest_v1/metrics/pageviews/top/en.wikiversity/all-access/2018/01/all-days"
choice = get_choice()
if choice == None:
break
elif choice == 1:
text = get_url(url)
lst = display_json(text)
dictionary = convert_dict(lst)
display_dict(dictionary)
elif choice == 2:
text = get_url(url)
lst = display_json(text)
dictionary = convert_dict(lst)
lst_2 = learning_project(dictionary)
convert(lst_2)
main()
To explain the learning project function, I had a bigger dictionary I needed to parse. So I turned the key into a string and parsed the key with RegEx. I then appended the value to the key and that created rows of lists. Then I turned the rows of lists into tuples, and created a list of tuples. Now I'm just trying to turn this back into a dictionary, but it is not working. Any help is greatly appreciated!
if you are getting errors with p = dict(lst_2) then your input data is not compliant with your requirement. You could make the conversion more robust by ensuring that list elements are always a two entry tuple.
p = dict( (*t,None,None)[:2] for t in lst_2 or [])
This will not fix the data but it may allow you to move forward and perhaps detect the faulty data by finding None key or None values in the resulting dictionary.
data = [('Heat_equation', 262), ('Portal:Tertiary_Educatio', 262),
('Help:Wiki_markup_example', 262), ('Quantum_mechanics', 262),
('IB_Language_A:_English_Language_and_Literature_Course_Materia', 261),
('Pulmonary_Plethor', 261)]
mydict = dict(data)
I am trying to print the results from all 3 names that are input, in a dictionary format. Current code below only prints out the last name. The 2 lines commented out (#) are what I was trying to change around to get it to work, clearly not doing it correctly.
def name():
count = 0
while (count < 5):
d = {}
qs = dict(Fname='first name', Lname='last name')
for k,v in qs.items():
d[k] = input('Please enter your {}: '.format(v))
#d['first name'].append(v)
#d['last name'].append(v)
count += 1
print(d)
name()
A few things that I'd change:
append each record (dictionary) to a list of entries.
(optional) Use a for-loop rather than a while as less lines of code.
return the entries list, rather than print it as it is a function so I like to have outputs.
So here's the corrected code:
def name():
entries = []
for count in range(5):
d = {}
qs = dict(Fname='first name', Lname='last name')
for k, v in qs.items():
d[k] = input('Please enter your {}: '.format(v))
entries.append(d)
return entries
print(name())
For testing purpose, I modified it to just except 2 entries, but we can still see that it works:
Please enter your last name: fish
Please enter your first name: bowl
Please enter your last name: cat
Please enter your first name: mat
[{'Lname': 'fish', 'Fname': 'bowl'}, {'Lname': 'cat', 'Fname': 'mat'}]
Hope! you got it right from Martijin Comments, For reference to other adding this code:
def name():
count = 0
listOfDict = [] #creating empty list
for count in range(3):
dict = {}
qs = dict(Fname = 'first name', Lname = 'last name' )
for k,v in qs.items():
d[k] = input('please enter your {}: '.format(v))
listOfDict.append(d) # adding each item to the list.
count += 1
print listOfDict
name()
This should work:
def name():
count = 0
while (count < 5):
d = {}
qs = dict(Fname='first name', Lname='last name')
for k,v in qs.items():
a = input('Please enter your {}: '.format(v))
d[v] = a
count += 1
print(d['first name'],d['last name'])
name()
You can use defaultdict to automatically create lists to store each entered value. The main idea is that you want to append each entered value to a collection of some type (e.g. list).
from collections import defaultdict
number_of_entries = 3
dd = defaultdict(list)
for _ in range(number_of_entries):
for key in ('first name', 'last_name'):
dd[key].append(input('please enter you {}: '.format(key)))
>>> print(dict(dd))
{'first name': ['Adam', 'Milton', 'Irving'],
'last_name': ['Smith', 'Friedman', 'Fisher']}
The function append below takes a pair which is an immutable tuple as a parameter. In the processing of the append it is necessary to enclose all values with start and end single quotes. Because the tuple values are immutable I cannot simply do this:
if item[1][0] != "'" and item[1][-1] != "'":
item[1] = "'{0}'".format(item[1])
self.keyvalues[item[0]] = item[1]
Hence the handling as follows:
if item[1][0] != "'" and item[1][-1] != "'":
self.keyvalues[item[0]] = "'{0}'".format(item[1])
else:
self.keyvalues[item[0]] = item[1]
Full code appears below.
Is there a more elegant way to add the key and value to the dictionary.
class section(object):
"""class to hold a section. name is name of section. keyvalues is a key
value dictionary of keys and values"""
def __init__(self, name):
self.name = name
self.keyvalues = {}
print "Constructed section:", name
def append(self, item):
"""add a key value pair to section"""
if len(item) != 2:
return False
else:
print "adding:", item, "to", self.name, "object"
# cannot do this because tuple is immutable
#item[1] = "'{0}'".format(item[1])
# Would there be a more elegant way of doing this - given that
# parameter must be a immutable tuple?
if item[1][0] != "'" and item[1][-1] != "'":
self.keyvalues[item[0]] = "'{0}'".format(item[1])
else:
self.keyvalues[item[0]] = item[1]
return True
def __repr__(self):
s = "contains\n"
for k, v in self.keyvalues.iteritems():
s += "\t{0}={1}\n".format(k, v)
return s
__str__ = __repr__
mysection = section("section1")
dnpair = ("key1", "value1")
mysection.append(dnpair)
print mysection
Since the tuple is not used again, just split it to separate variables.
key, value = item
if value[0] != "'" and value[-1] != "'":
value = "'{0}'".format(value)
self.keyvalues[key] = value
Elegant is subjective, but this is the most elegant solution I could come up with. It allows value manipulation by passing it off to a function. Also the ugly
if item[1][0] != "'" and item[1][-1] != "'":
becomes
if not value[0] == value[-1] == "'":
Here's the full code with the modified append and newly created quote_wrap method.
def append(self, item):
"""add a key value pair to section"""
if len(item) != 2:
return False
else:
print( "adding:", item, "to", self.name, "object")
self.keyvalues[item[0]] = self.quote_wrap(item[1])
return True
def quote_wrap(self, value):
if not value[0] == value[-1] == "'":
value = "'{}'".format(value)
return value
This code is showing only the last item of a list of dictionaries:
def chooseOneServer():
dara = websvc()
i=0
for item in dara:
for key,value in item.items() :
if key == '1' :
servers = ( ('i',value), )
i +=1
return servers
I've already answered this in the comments of your last question, but here it is again:
def chooseOneServer():
dara = websvc()
i=0
servers = []
for item in dara:
for key,value in item.items() :
if key == '1':
servers.append(('i',value))
i += 1
return servers
You just add each item to a list, rather than overwriting the same tuple each time.